def get_claims(security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme)): if security_scopes.scopes: authenticate_value = f'Bearer scope="{security_scopes.scope_str}"' else: authenticate_value = f"Bearer" try: claims = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.TOKEN_ALGORITHM]) token = TokenSchema.parse_obj(claims) if token.type != TokenType.access: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Requires access token") except JWTError: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": authenticate_value}, ) logger.debug(f"Required scope: {security_scopes.scopes}, Token Scopes: {token.scopes}") for scope in security_scopes.scopes: if scope not in token.scopes: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Insufficient permissions", headers={"WWW-Authenticate": authenticate_value}, ) return claims
def get_room(room_id): try: room = Room.get(room_id) logger.debug(room) return room except InstanceNotFound: raise HTTPException(status_code=404, detail="Could not find lobby")
async def on_join(self, sid: PlayerSID, msg: JoinMessage) -> None: """ Player requests to join a game room """ # TODO: Fix join ID identity = {"id": "FIXME"} player: Player = Player.create( name=msg.name, room=msg.roomid, user_id=identity["id"] if identity is not None else None, sid=sid, ) logger.debug("Player requested to join a room") player_id = player.id try: room: Room = Room.get(msg.roomid) except InstanceNotFound as e: raise NoSuchRoom from e if room.status != "lobby": raise GameAlreadyStarted elif room.private: raise NoSuchRoom else: logger.debug(f"Registering user") await RegisterMessage(roomid=msg.roomid, playerid=player_id).send(self, to=room.server_sid)
def make_move(self, player_id: PlayerId, player_role: Optional[GameRole], move: Move): logger.debug(f"Making move for role: {player_role}") col: int = move["col"] row: int = move["row"] grid: List[List[Optional[GameRole]]] = self.board["grid"] if grid[row][col] is not None: raise IllegalMove(details="Attempted to play in square that is already occupied") grid[row][col] = player_role if ( all(grid[row][i] == player_role for i in range(3)) or all(grid[i][col] == player_role for i in range(3)) or all(grid[i][i] == player_role for i in range(3)) or all(grid[i][2 - i] == player_role for i in range(3)) ): # Player won self.winner = player_id raise GameCompleted elif all(cell is not None for row in grid for cell in row): # Match is a draw self.winner = None raise GameCompleted else: next_role = player_o if player_role == player_x else player_x self.turn = self.roles[next_role]
async def callback(self, msgtype=None, *args): if msgtype == "fail": error = args[0] raise all_exceptions[error["error"]]( f"{error['details']!r},\nReceived in response to: {self!r}") elif self._callback: logger.debug(f"Recv Callback: msgtype={msgtype!r}, args={args!r}") await self._callback(*args)
async def on_playermove(self, msg: PlayerMoveMessage): """ Player sends a move """ with self.lock: assert self.room_id is not None try: logger.debug("Starting player move") self.game.move(msg.playerid, msg.move) logger.debug("Finished player move") await GameUpdateMessage( visibility="broadcast", roomid=msg.roomid, board=self.game.show_board(), turn=self.game.turn, epoch=self.game.movenumber, stateid=msg.stateid, ).send(sio=self) except GameCompleted: self.game.playing = False await GameUpdateMessage( visibility="broadcast", roomid=msg.roomid, board=self.game.show_board(), turn=None, epoch=self.game.movenumber, stateid=msg.stateid, finish=Finish( normal=True, scores=self.game.score(), ), ).send(sio=self) if settings.RUN_ONCE: await self.disconnect() else: self.game = all_games[self.game_name]() await self.initialize() except IllegalMove as e: logger.exception(e) await GameUpdateMessage( roomid=self.room_id, visibility="broadcast", epoch=self.game.movenumber, board=self.game.show_board(), turn=None, finish=Finish( normal=False, reason=e.details, fault=msg.playerid, scores={ p: (-1 if p == msg.playerid else 1) for p in self.game.players }, ), ).send(sio=self)
def get_move(self) -> Move: assert self.board is not None assert self.gamerole is not None player_pits = self.board[f"pits_{self.gamerole}"] legal_moves = [{ "move": idx } for idx, pits in enumerate(player_pits) if pits > 0] logger.debug(self.board) if logger.isEnabledFor(logging.DEBUG): sleep(1.5) return Move(random.choice(legal_moves))
async def on_createroom(self, sid: GameServerSID, msg: CreateRoomMessage) -> None: """ Server requests to create a game room """ room = Room.create(name=msg.name, game=msg.game, maxplayers=msg.maxplayers, server_sid=sid) logger.debug(f"Registered Gameserver with room: {room.id}") await RoomCreatedMessage(roomid=room.id).send(self, to=sid)
def update(self, board: Board, turn: Optional[PlayerId] = None) -> Optional[Move]: """ Can be overridden to do processing even when not the player's turn Also can be overridden if players want to keep track of previous states :param turn: ID of player who'd turn it is :param board: New board state """ self.board = board if turn == self.player_id and turn is not None: logger.debug("Our move to play") return self.get_move() else: return None
def make_move(self, player_id: PlayerId, player_role: Optional[GameRole], move: Move): m: str = move["move"] if m not in ["scissors", "paper", "rock"]: raise ValueError logger.debug(f"Player Role: {player_role}") if player_role == player_a: self.board[player_a] = m self.turn = self.roles[player_b] elif m == self.board[player_b]: self.board = Board({player_a: None, player_b: None}) self.turn = self.roles[player_a] else: self.board[player_b] = m raise GameCompleted
async def send(self, sio, to: Optional[SioSID] = None, callback: Optional[Callable] = None): message_name = self.__class__.__name__[:-7].lower() self._callback = callback if to is None: logger.debug(f"Sending message {message_name}:\n{self!r}") await sio.emit(message_name, self.to_dict(), callback=self.callback) else: logger.debug( f"Sending message {message_name} to {to!r}:\n{self!r}") await sio.emit(message_name, self.to_dict(), room=to, callback=self.callback)
def refresh(response: Response, refresh_token: Optional[str] = Cookie(None)): if refresh_token is None: logger.debug("No refresh token") return {"success": False} try: claims = jwt.decode(refresh_token, settings.SECRET_KEY, algorithms=[settings.TOKEN_ALGORITHM]) if claims["type"] != "refresh": logger.warning("Attempted refresh with not refresh token") return {"success": False} try: user = User.get(claims["sub"]) return set_tokens(response, user) except InstanceNotFound: logger.warning( f"User from refresh token not found: {claims['sub']}") return {"success": False} except JWTError as e: logger.warning(f"JWT Error in refresh token: {e!r}") return {"success": False}
async def wrapper(sio: SocketioType, *args): if len(args) == 1: [data] = args sid = None else: [sid, data] = args if data is None: data = dict() m = {k: v for k, v in data.items() if v is not None} try: msg = message_type.parse_obj(m) except ValidationError as e: logger.debug( f"Receieved invalid data:\n{json.dumps(data, indent=2)}") logger.warning( f"Validation encountered for {f.__name__}: {e!r}") return ( "fail", { "error": "InputValidationError", "details": e.json(), }, ) try: if sid is None: await f(sio, msg=msg) else: return await f(sio, sid=sid, msg=msg) except AsimovErrorBase as e: logger.exception(e) return ( "fail", { "error": e.__class__.__name__, "details": e.details, }, )
def add_player(bot: Bot, tournament: Tournament) -> Participant: logger.debug("Getting tournament lock: %s", tournament.id) with tournament.lock(): logger.debug("Got lock for tournament: %s", tournament.id) participants = tournament.participants participant_ids = {participant.bot.id for participant in participants} if bot.id in participant_ids: raise AlreadyInTournament index = max(x.index for x in participants) + 1 if participants else 1 participant = Participant.create(index=index, bot=bot, tournament=tournament) for opponent in participants: if opponent.disqualified: continue Match.create( index=100000 * index + opponent.index, tournament=tournament, players=[participant, opponent], state=MatchState.pending, ) return participant
def asign_role(self, player_id: PlayerId) -> Optional[GameRole]: logger.debug(f"Currently assigned roles: {self.roles}") available = list({player_o, player_x} - set(self.roles)) logger.debug(f"Available roles: {available}") role = random.choice(available) logger.debug(f"Assigning role {player_id} -> {role}") self.players[player_id] = role self.roles[role] = player_id return role
def show_board(self) -> Board: board_repr = "\n -+-+-\n ".join( "|".join(" " if cell is None else cell for cell in row) for row in self.board["grid"] ) logger.debug(f"Board:\n {board_repr}") return self.board
async def on_gameupdate(self, sid: GameServerSID, msg: GameUpdateMessage) -> None: """ Server notifies of a game state change """ if msg.visibility == "private": if msg.playerid is None: raise InputValidationError( details= "error: 'playerid' must be provided when visibility is private" ) else: if msg.playerid is not None: raise InputValidationError( details= "error: 'playerid' cannot be provided unless visibility is private" ) if msg.epoch is None: raise InputValidationError( details= "error: 'epoch' is required for non-private messages") room, player = get_room_player(sid, msg.roomid, msg.playerid) with room.lock(timeout=0.5, sleep=0.02): if msg.finish is not None: logger.info("Game finished") await GamestateMessage.parse_obj(msg.to_dict() ).send(self, to=room.broadcast_sid) room.update(status="finished") new_status = "finished" if room.status == "finished" else "playing" if msg.visibility == "private": room.update(status=new_status, turn=msg.turn) assert player is not None await GamestateMessage( board=msg.board, turn=msg.turn, roomid=msg.roomid, playerid=msg.playerid, epoch=msg.epoch, ).send(self, to=player.sid) else: if room.status == "finished": room.update(board=msg.board, turn=None) else: room.update(status=new_status, turn=msg.turn) if msg.visibility == "broadcast": r = GamestateMessage( board=msg.board, turn=msg.turn, roomid=msg.roomid, playerid=msg.playerid, epoch=msg.epoch, ) logger.debug( f"room.id={room.id}, room.broadcast_sid={room.broadcast_sid}" ) await r.send(sio=self, to=room.broadcast_sid) try: state = GameState.get(msg.stateid) if state.room is not None and state.room.id != msg.roomid: raise InstanceNotFound except InstanceNotFound: state_args = { "room_id": msg.roomid, "epoch": msg.epoch, "board": msg.board, "turn": msg.turn, } GameState.create( **{k: v for k, v in state_args.items() if v is None}) else: state.update(epoch=msg.epoch, board=msg.board, turn=msg.turn) room.update( status=new_status, board=msg.board, turn=msg.turn, )