def register_player(player): """ We keep a list of player in our redis in order to check things like ownership between player and user and to be able to enumerate all known players. This Redis key serves as an index :param player: Dictionary of player :return: True player was successfully registered """ players_data = redis.get('players') players = [] # If there are no players, then we create an empty list if players_data is not None: players = json.loads(players_data.decode('utf-8')) players.append(player) redis.set('players', json.dumps(players)) # Now we create a board for the player once it has been registered on a game board = Board(player_id=player['player_id'], game_id=player['game_id'], board_id=player['board_id'], persistence_provider=redis) board.expand() board.save() # Release the memory allocation to keep low overhead board = None players = None return True
def update_game_index(game_id, gameinfo): """ Updates the persistence provider, removing a spot from it :param game_id: Game id :param gameinfo: full static metadata of a game :return: True if game was successfully updated """ games_data = persistence_provider.get('games') games = [] newgames = [] # If there are no games, then we create an empty list if games_data is not None: games = json.loads(games_data.decode('utf-8')) key = None try: for game in games: if game_id == game["game_id"]: newgames.append(gameinfo) else: newgames.append(game) except: return False persistence_provider.set('games', json.dumps(newgames)) games = None newgames = None return True
def get_board(board_id): """ This endpoint allows a user to get it's current board. This method will only allow the player's own board. If another player's board is attempted to access, then a 401 Not authorized error code should be returned. :return: A json representation of the player's board. """ if board_id is not None: # Check current identity matches owner of the board. board_data = redis_store.get(board_id) board = json.loads(board_data) if verify_ownership(player_id=board['player_id'], user_id=current_identity.id): # If the user is the actual owner of the board, then we can provide the complete # and updated representation of the board. board = Board(game_id=board['game_id'], player_id=board['player_id'], board_id=board_id, persistence_provider=redis_store) board.load(board_data) result = board.export_state() board = None return jsonify(result), 200 return jsonify({ "Error": True, "Message": "You are not the owner of the requested board. Only owner can request he's board" }), 401 return jsonify({ "Error": True, "Message": "No board id provided" }), int(HTTPStatus.BAD_REQUEST)
def update_player_index(player_id, player_info): """ Updates the persistence provider, removing a spot from it :param player_id: Player id :param player_info: full static metadata of a player :return: True if game was successfully updated """ players_data = redis.get('players') players = [] newplayers = [] # If there are no games, then we create an empty list if players_data is not None: players = json.loads(players_data.decode('utf-8')) key = None try: for player in players: if player_id == player["player_id"]: newplayers.append(player_info) else: newplayers.append(player) except: return False redis.set('players', json.dumps(newplayers)) players = None newplayers = None return True
def get_redis_status(): """ in order to check current REDIS status, we will submit some data and then we will try to retrieve it just to verify we can successfully create a connection with the REDIS Store. :return: JSON object with result """ # First we save some data to a given key redis_store.set("Battleship Version", "v1") redis_store.set("Battleship Stack", "Python + Flask + REDIS + MongoDB") # Now we retrieve the data result = { "Battleship Version": redis_store.get("Battleship Version"), "Stack": redis_store.get("Battleship Stack"), "Redis Status": "OK" } return jsonify(result), int(HTTPStatus.OK)
def get_player(player_id): """ Searches the REDIS index and loads the instance of player associated to the given player id. :param player_id: The id of the player to load """ player_data = redis.get(player_id) if player_data is not None: player = Player(None, None, redis) player.load(player_id) return player return None
def get_game_list(): availible_games = [] games_data = persistance_provider.get('games') if games_data is not None: games = json.loads(games_data) try: for game in games: if game["game_status"] == str(GameStatus.WAITING_FOR_PLAYERS): availible_games.append(game) return jsonify(availible_games) except: return jsonify({"Error": "Unable to fetch games" }), HTTPStatus.INTERNAL_SERVER_ERROR return jsonify({"Error": "No games found, create a new one?"}), HTTPStatus.NOT_FOUND
def register_game(game): """ We keep a list of games in our persistence_provider in order to check things open spots in game and to be able to enumerate all known games. This game persistence_provider key serves as an index :param game: Dictionary of game :return: True game was successfully registered """ games_data = persistence_provider.get('games') games = [] # If there are no games, then we create an empty list if games_data is not None: games = json.loads(games_data.decode('utf-8')) games.append(game) persistence_provider.set('games', json.dumps(games)) games = None return True
def verify_ownership(player_id, user_id): """ Checks on the players index if a given player id is owned by the given user id. :param player_id: The id of the player :param user_id: The user who supposedly owns the given player id :return: """ players_data = redis.get('players') players = [] # If there are no players, then we create an empty list if players_data is not None: app.logger.info('Reading players data... for player: [' + player_id + '] with user: [' + user_id + ']') players = json.loads(players_data) app.logger.info('Players loaded... List: ' + json.dumps(players)) try: for player in players: if player['player_id'] == player_id and player[ 'user_id'] == user_id: return True return False except: return False
def post_torpedo(board_id): """ --------------------------------------------------------------------------------- This method allows to drop a torpedo in a given pair of coordinates on a board belonging to an opponent that is currently playing within the same game instance. The boards are uniquely identified by a key. In order to specify the coordinates that are going to indicate the location where the torpedo is going to be sent, the following payload must be provided (example values): { "x_coordinate": 3, "y_coordinate": 4, "shooter": "56c142a9-8946-4b50-9e12-e12867573d3f" } :param board_id: The id of the board to where the :return: A json payload containing the result of the bombing operation in the given board. --------------------------------------------------------------------------------- """ torpedo_coordinates = request.get_json() board_data = redis_store.get(board_id) # First we check if the board instance actually exists within redis store. app.logger.info('Checking board...') if board_data is not None: brt = json.loads(board_data.decode('utf-8')) # Next we verify the user is not trying to send torpedo to his own board. board = Board(game_id=brt['game_id'], player_id=brt['player_id'], board_id=brt['board_id'], persistence_provider=redis_store) app.logger.info('Instantiating board...') board.load(board_data) app.logger.info('board loaded with data: ' + str(board_data)) app.logger.info('Getting shooter...') shooter = get_player(torpedo_coordinates['shooter']) app.logger.info('Getting receiver...') receiver = get_player(board.get_player_id()) if board.get_owner_id( ) != current_identity.id and current_identity.id == shooter.get_owner( ): app.logger.info('Valid shooter shooting valid board') game = Game(None, None, persistence_provider=redis_store ) #instace as null to later load from id game.load(game_id=brt['game_id']) if game.static_metadata( )["moves_next"] != torpedo_coordinates['shooter']: return jsonify( ErrorResponse( 'Trying to shoot when its not your turn', 'You are trying to shoot but its not your turn').get() ), int(HTTPStatus.BAD_REQUEST) if torpedo_coordinates is not None: result = board.shoot(torpedo_coordinates['x_coordinate'], torpedo_coordinates['y_coordinate']) if result >= 0: # We update the state on the redis store board.save() app.logger.info('Torpedo was sent: shooter: [' + current_identity.id + '] destination ->> [' + board.get_player_id() + ']') if not shooter.is_alive() or not receiver.is_alive(): app.logger.error( 'Somebody is wasting bullets on a dead player') return jsonify( ErrorResponse( 'Trying to torpedo dead player', 'Either you are dead, or you\'re tryiing to shoot a dead player;' ).get()), int(HTTPStatus.BAD_REQUEST) if shooter is not None and receiver is not None and receiver: app.logger.info('Shoot result was: [' + str(result) + ']') if result > 0: shooter.add_points(result) receiver.update_fleet_value(result) app.logger.info('Boat was damaged by torpedo...') app.logger.info('moving to next player...') move_to_next_player(board.get_game_id()) app.logger.info('building result...') s = shooter.export_state() r = receiver.export_state() shooter = None receiver = None return jsonify({ "result_code": result, "shooter": s, "receiver": r }), HTTPStatus.CREATED else: app.logger.error( 'If you get here...This shit is nasty... players not found for transaction' ) return jsonify({ 'Error': 'Internal player reference error', 'Message': 'Players in transaction could not be found' }) else: app.logger.error( 'Some stupid player tried to shoot an already shot location' ) return jsonify({"result_code": -1}), HTTPStatus.BAD_REQUEST else: app.logger.error( 'Some stupid player tried to shoot a torpedo into a non-valid location' ) return jsonify( ErrorResponse( 'Invalid coordinates for torpedo', 'You cannot shoot to nowhere. Provide a valid json payload to shoot' ).get()), int(HTTPStatus.BAD_REQUEST) else: return jsonify({ 'Error': 'Invalid torpedo operation', 'Message': 'Dude, you cannot shoot your own crappy boats nor steal identities...!' }), int(HTTPStatus.BAD_REQUEST) else: return jsonify( ErrorResponse( 'Unable to find board', 'The provided board is does not correspond to a valid board'). get()), int(HTTPStatus.NOT_FOUND)