def perform_move(game_id, player_id, move_dto): """Performs a move operation on the game.""" location = mapper.dto_to_move_action(move_dto) _ = interactors.OverduePlayerInteractor(game_repository()) interactor = interactors.PlayerActionInteractor(game_repository()) _try(lambda: interactor.perform_move(game_id, player_id, location)) DatabaseGateway.get_instance().commit()
def remove_unobserved_games(unobserved_period): """ Uses UnobservedGamesInteractor to remove games which have not been observed for the given period """ interactor = interactors.UnobservedGamesInteractor(game_repository(), logging.get_logger()) removed_ids = _try(lambda: interactor.remove_unobserved_games(unobserved_period)) for game_id in removed_ids: logging.get_logger().remove_game(game_id) DatabaseGateway.get_instance().commit()
def add_player(game_id, player_request_dto): """ Adds a player to a game. Creates the game if it does not exist. After adding the player, the game is started. :param game_id: specifies the game :param player_request_dto: if this parameter is given, it contains information about the type of player to add :return: the added player """ _ = interactors.OverduePlayerInteractor(game_repository(), logging.get_logger()) _ = interactors.UpdateOnTurnChangeInteractor(game_repository()) game = _get_or_create_game(game_id) is_bot, computation_method = mapper.dto_to_type(player_request_dto) player_name = mapper.dto_to_player_name(player_request_dto) player_id = _try(game.unused_player_id) player = None if not is_bot: player = Player(player_id, player_name=player_name) else: player = _try(lambda: bots.create_bot(compute_method=computation_method, url_supplier=URLSupplier(), player_id=player_id, player_name=player_name)) _try(lambda: game.add_player(player)) DatabaseGateway.get_instance().update_game(game_id, game) DatabaseGateway.get_instance().commit() logging.get_logger().add_player(player_id, game_id=game_id, is_bot=is_bot, num_players=len(game.players)) return mapper.player_to_dto(player)
def get_game_state(game_id): """ Returns the game state """ _ = interactors.OverduePlayerInteractor(game_repository()) interactor = interactors.ObserveGameInteractor(game_repository()) game = _try(lambda: interactor.retrieve_game(game_id)) game_state = mapper.game_state_to_dto(game) DatabaseGateway.get_instance().commit() return game_state
def perform_shift(game_id, player_id, shift_dto): """Performs a shift operation on the game.""" location, rotation = mapper.dto_to_shift_action(shift_dto) _ = interactors.OverduePlayerInteractor(game_repository(), logging.get_logger()) _ = interactors.UpdateOnTurnChangeInteractor(game_repository()) interactor = interactors.PlayerActionInteractor(game_repository()) _try(lambda: interactor.perform_shift(game_id, player_id, location, rotation)) DatabaseGateway.get_instance().commit()
def change_player_name(game_id, player_id, player_name_dto): """ Renames a player :param game_id: specifies the game :param player_id: specifies the player to remove :param player_name_dto: contains the new player name.""" new_name = mapper.dto_to_player_name(player_name_dto) interactors.PlayerInteractor(game_repository()).change_name(game_id, player_id, new_name) DatabaseGateway.get_instance().commit()
def get_game_state(game_id): """ Returns the game state """ _ = interactors.OverduePlayerInteractor(game_repository(), logging.get_logger()) _ = interactors.UpdateOnTurnChangeInteractor(game_repository()) action_timeout = timedelta(seconds=int(current_app.config["OVERDUE_PLAYER_TIMEDELTA_S"])) interactor = interactors.ObserveGameInteractor(game_repository(), action_timeout=action_timeout) game, remaining_timedelta = _try(lambda: interactor.retrieve_game(game_id)) game_state = mapper.game_state_to_dto(game, remaining_timedelta) DatabaseGateway.get_instance().commit() return game_state
def test_interactor__when_game_notifies_turn_listeners__updates_player_action_timestamp( ): game, _ = setup_test() data_access = DatabaseGateway(settings={"DATABASE": "foo"}) game_repository = interactors.GameRepository(data_access) game_repository.update_action_timestamp = Mock() _ = interactors.OverduePlayerInteractor(game_repository, logger) data_access._notify_listeners(game) game._notify_turn_listeners() game_repository.update_action_timestamp.assert_called_once_with( game, matchers.time_close_to(datetime.now()))
def delete_player(game_id, player_id): """ Removes a player from a game :param game_id: specifies the game :param player_id: specifies the player to remove """ _ = interactors.OverduePlayerInteractor(game_repository()) game = _load_game_or_throw(game_id, for_update=True) _try(lambda: game.remove_player(player_id)) DatabaseGateway.get_instance().update_game(game_id, game) DatabaseGateway.get_instance().commit() return ""
def change_game(game_id, game_request_dto): """ Changes game setup. Currently, the only option is to change the maze size. This will restart the game. :param game_id: specifies the game. Has to exist. :param game_request_dto: contains the new maze size.""" new_size = mapper.dto_to_maze_size(game_request_dto) _ = interactors.OverduePlayerInteractor(game_repository()) game = _load_game_or_throw(game_id) new_board = _try(lambda: factory.create_board(maze_size=new_size)) _try(lambda: game.replace_board(new_board)) DatabaseGateway.get_instance().update_game(game_id, game) DatabaseGateway.get_instance().commit()
def create_app(test_config=None): """ basic Flask app setup. Creates the instance folder if not existing """ app = Flask(__name__, instance_relative_config=True, static_folder="../static", static_url_path="") app.config.from_mapping( SECRET_KEY='dev', PROFILE=False, DATABASE=os.path.join(app.instance_path, 'labyrinth.sqlite'), LIBRARY_PATH=os.path.join(app.instance_path, 'lib'), ) if test_config is None: app.config.from_pyfile('config.py', silent=True) else: app.config.from_mapping(test_config) if app.config["PROFILE"]: app.wsgi_app = ProfilerMiddleware(app.wsgi_app, profile_dir=os.path.join(app.instance_path), stream=None) try: os.makedirs(app.instance_path) except OSError: pass from . import api app.register_blueprint(api.API) from . import game_management app.register_blueprint(game_management.GAME_MANAGEMENT) from labyrinth.database import DatabaseGateway app.before_first_request(lambda: DatabaseGateway.init_database()) app.teardown_request(lambda exc: DatabaseGateway.close_database()) mimetypes.add_type('application/wasm', '.wasm') @app.route('/') def index(): """ Serves the 'static' part, i.e. the Vue application """ return app.send_static_file("index.html") return app
def create_app(test_config=None): """ basic Flask app setup. Creates the instance folder if not existing """ # Imports inside here so the package can be imported without the dependency to Flask # import mimetypes import os from flask import Flask from werkzeug.middleware.profiler import ProfilerMiddleware import labyrinth.event_logging as logging app = Flask(__name__, instance_relative_config=True, static_folder="../../web-client/dist", static_url_path="") app.config.from_mapping(SECRET_KEY='dev', PROFILE=False, ENABLE_INFLUXDB_LOGGING=False, JSON_SORT_KEYS=False, DATABASE=os.path.join(app.instance_path, 'labyrinth.sqlite'), LIBRARY_PATH=os.path.join(app.instance_path, 'lib')) if test_config is None: app.config.from_pyfile('config.py', silent=True) else: app.config.from_mapping(test_config) if app.config["ENABLE_INFLUXDB_LOGGING"]: app.before_request(lambda: logging.create_logger( app.config["INFLUXDB_URL"], app.config["INFLUXDB_TOKEN"])) if app.config["PROFILE"]: app.wsgi_app = ProfilerMiddleware(app.wsgi_app, profile_dir=os.path.join( app.instance_path), stream=None) if test_config is None: from labyrinth.scheduler import scheduler, schedule_remove_overdue_players, schedule_remove_unobserved_games scheduler.init_app(app) schedule_remove_overdue_players() schedule_remove_unobserved_games() scheduler.start() try: os.makedirs(app.instance_path) except OSError: pass from . import api app.register_blueprint(api.API) from . import analytics app.register_blueprint(analytics.API) from . import game_management app.register_blueprint(game_management.GAME_MANAGEMENT) from labyrinth.database import DatabaseGateway app.before_first_request(lambda: DatabaseGateway.init_database()) app.teardown_request(lambda exc: DatabaseGateway.close_database()) mimetypes.add_type('application/wasm', '.wasm') @app.route('/') def index(): """ Serves the 'static' part, i.e. the Vue application """ return app.send_static_file("index.html") @app.route('/version') def version(): """ Returns version as 3-tuple """ return version_info._asdict() return app
def remove_unobserved_games(unobserved_period): """ Uses UnobservedGamesInteractor to remove games which have not been observed for the given period """ interactor = interactors.UnobservedGamesInteractor(game_repository()) _try(lambda: interactor.remove_unobserved_games(unobserved_period)) DatabaseGateway.get_instance().commit()
def _load_game_or_throw(game_id, for_update=False): game = DatabaseGateway.get_instance().load_game(game_id, for_update=for_update) if game is None: raise exceptions.GAME_NOT_FOUND_API_EXCEPTION return game
def _create_game(game_id): game = factory.create_game(game_id=game_id) DatabaseGateway.get_instance().create_game(game, game_id) logging.get_logger().add_game(game_id) return game
def _get_or_create_game(game_id): game = DatabaseGateway.get_instance().load_game(game_id) if game is None: game = _create_game(game_id) return game
def game_repository(): return interactors.GameRepository(DatabaseGateway.get_instance())
def _create_game(game_id): game = factory.create_game(game_id=game_id) DatabaseGateway.get_instance().create_game(game, game_id) return game
def remove_overdue_players(overdue_timedelta): """ Uses OverduePlayerInteractor to remove players which block the game by not performing actions """ interactor = interactors.OverduePlayerInteractor(game_repository(), logging.get_logger()) _try(lambda: interactor.remove_overdue_players(overdue_timedelta)) DatabaseGateway.get_instance().commit()
def managed_gateway(self): """ Creates a database gateway as a context manager It should only be necessary to retrieve this in non-request contexts. """ return DatabaseGateway(self._data_access.settings)