Cleanups
This commit is contained in:
@ -53,7 +53,9 @@ async def get_game_info(
|
||||
)
|
||||
|
||||
|
||||
@router.post("/game", response_model=StartGameResponseDto)
|
||||
@router.post(
|
||||
"/game", response_model=StartGameResponseDto, status_code=status.HTTP_201_CREATED
|
||||
)
|
||||
async def start_game(
|
||||
body: StartGameRequestDto,
|
||||
engine: GameEngine = Depends(get_game_engine),
|
||||
@ -72,7 +74,6 @@ async def start_game(
|
||||
@router.get(
|
||||
"/player/{uuid}",
|
||||
response_model=PlayerInfoResponseDto,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
responses={
|
||||
status.HTTP_403_FORBIDDEN: {
|
||||
"model": ErrorResponseDto,
|
||||
|
||||
@ -5,6 +5,7 @@ from typing import Optional
|
||||
|
||||
from hopper.enums import Direction, PlayerMoveResult
|
||||
from hopper.errors import Collision, PositionOutOfBounds
|
||||
from hopper.interfaces import SendGameStateInterface
|
||||
from hopper.models.board import (
|
||||
BOARD_DUMP_CHARS,
|
||||
BoardLayout,
|
||||
@ -17,12 +18,13 @@ from hopper.models.board import (
|
||||
)
|
||||
from hopper.models.player import Player, PlayerList, Position
|
||||
from hopper.watchdog import InactivityWatchdog
|
||||
from hopper.ws_server import WSServer
|
||||
from settings import settings
|
||||
|
||||
|
||||
class GameEngine:
|
||||
def __init__(self, board: GameBoard, ws_server: Optional[WSServer] = None) -> None:
|
||||
def __init__(
|
||||
self, board: GameBoard, ws_server: Optional[SendGameStateInterface] = None
|
||||
) -> None:
|
||||
self.board = board
|
||||
self.ws_server = ws_server
|
||||
self.players = PlayerList()
|
||||
@ -163,7 +165,7 @@ class GameEngineFactory:
|
||||
board_width: int,
|
||||
board_height: int,
|
||||
obstacle_count: int = 0,
|
||||
ws_server: Optional[WSServer] = None,
|
||||
ws_server: Optional[SendGameStateInterface] = None,
|
||||
) -> GameEngine:
|
||||
board = GameBoard(
|
||||
width=board_width,
|
||||
@ -188,7 +190,9 @@ class GameEngineFactory:
|
||||
return game
|
||||
|
||||
@staticmethod
|
||||
def create_default(ws_server: Optional[WSServer] = None) -> GameEngine:
|
||||
def create_default(
|
||||
ws_server: Optional[SendGameStateInterface] = None,
|
||||
) -> GameEngine:
|
||||
return GameEngineFactory.create(
|
||||
board_width=settings.board.WIDTH,
|
||||
board_height=settings.board.HEIGHT,
|
||||
|
||||
6
hopper/interfaces.py
Normal file
6
hopper/interfaces.py
Normal file
@ -0,0 +1,6 @@
|
||||
from typing import Protocol
|
||||
|
||||
|
||||
class SendGameStateInterface(Protocol):
|
||||
async def send_game_state(self) -> None:
|
||||
...
|
||||
@ -5,14 +5,18 @@ import time
|
||||
from threading import Thread
|
||||
from typing import Optional
|
||||
|
||||
from hopper.interfaces import SendGameStateInterface
|
||||
from hopper.models.player import PlayerList
|
||||
from hopper.ws_server import WSServer
|
||||
from settings import settings
|
||||
|
||||
|
||||
class InactivityWatchdog(Thread):
|
||||
def __init__(
|
||||
self, players: PlayerList, ws_server: Optional[WSServer] = None, *args, **kwargs
|
||||
self,
|
||||
players: PlayerList,
|
||||
ws_server: Optional[SendGameStateInterface] = None,
|
||||
*args,
|
||||
**kwargs,
|
||||
) -> None:
|
||||
self.players = players
|
||||
self.ws_server = ws_server
|
||||
|
||||
@ -12,20 +12,20 @@ from settings import settings
|
||||
|
||||
|
||||
class WSServer(Thread):
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
self.connected_clients = set[WebSocketServerProtocol]()
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
async def handler(self, websocket: WebSocketServerProtocol) -> None:
|
||||
"""New handler instance spawns for each connected client"""
|
||||
self.connected_clients.add(websocket)
|
||||
logging.info(f"Add client: {websocket.id}")
|
||||
|
||||
try:
|
||||
# send initial game state to connected client
|
||||
await self.send_game_state_to_client(websocket)
|
||||
# loop and do nothing while client is connected
|
||||
connected = True
|
||||
while connected:
|
||||
try:
|
||||
message = await websocket.recv()
|
||||
# we're expecting nothing from client, but read if client sends a message
|
||||
await websocket.recv()
|
||||
except ConnectionClosedOK:
|
||||
connected = False
|
||||
finally:
|
||||
@ -49,11 +49,13 @@ class WSServer(Thread):
|
||||
async def send_game_state_to_client(
|
||||
self, websocket: WebSocketServerProtocol
|
||||
) -> None:
|
||||
"""Send game state to the client"""
|
||||
message = self._create_game_state_message()
|
||||
logging.debug(f"Sending game state to client: {websocket.id}")
|
||||
await websocket.send(message)
|
||||
|
||||
async def send_game_state(self) -> None:
|
||||
"""Broadcast game state to all connected clients"""
|
||||
if not self.connected_clients:
|
||||
return
|
||||
|
||||
@ -77,4 +79,5 @@ class WSServer(Thread):
|
||||
await asyncio.Future() # run forever
|
||||
|
||||
def run(self) -> None:
|
||||
self.connected_clients = set[WebSocketServerProtocol]()
|
||||
asyncio.run(self.run_async())
|
||||
|
||||
Reference in New Issue
Block a user