From 6111d07f09e940a9c0553ad9a496cf8bb1f18c1f Mon Sep 17 00:00:00 2001 From: Eden Kirin Date: Thu, 30 Mar 2023 18:53:24 +0200 Subject: [PATCH] WSMessage object --- frontend/index.html | 23 ++++++++++++++++------- hopper/models/config.py | 2 ++ hopper/models/product.py | 8 ++++++++ hopper/models/ws_dto.py | 24 ++++++++++++++++++++++++ hopper/ws_server.py | 9 ++++----- 5 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 hopper/models/product.py diff --git a/frontend/index.html b/frontend/index.html index 6a4c50a..1127c46 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -115,6 +115,13 @@ renderCellContent(position, BOARD_ICONS.DESTINATION); } + function renderGameDump(data) { + createBoard(data.board); + renderObstacles(data.layers) + renderDestination(data.destination.position); + renderPlayerList(data.players); + renderPlayers(data.players); + } function wsConnect() { let ws = new WebSocket('ws://localhost:8011'); @@ -123,14 +130,16 @@ }; ws.onmessage = (e) => { - const data = JSON.parse(e.data); - console.log("WS message received:", data) + const wsMessage = JSON.parse(e.data); + console.log("WS message received:", wsMessage) - createBoard(data.board); - renderObstacles(data.layers) - renderDestination(data.destination.position); - renderPlayerList(data.players); - renderPlayers(data.players); + switch (wsMessage.message) { + case "game_dump": + renderGameDump(wsMessage.data); + break; + default: + console.error("Unknown message:", wsMessage) + } }; ws.onclose = (e) => { diff --git a/hopper/models/config.py b/hopper/models/config.py index 85141b6..3a5a6f9 100644 --- a/hopper/models/config.py +++ b/hopper/models/config.py @@ -3,6 +3,7 @@ from dataclasses import dataclass from typing import List, Optional from hopper.models.player import Player +from hopper.models.product import Product @dataclass @@ -44,4 +45,5 @@ class Settings: ws_server: WSServerSettings purchase_timeout: int = 10 # seconds log_level: int = logging.INFO + products: Optional[List[Product]] = None debug: Optional[DebugSettings] = None diff --git a/hopper/models/product.py b/hopper/models/product.py new file mode 100644 index 0000000..1dcd976 --- /dev/null +++ b/hopper/models/product.py @@ -0,0 +1,8 @@ +from dataclasses import dataclass, field +import uuid + + +@dataclass +class Product: + name: str + uuid: str = field(default_factory=lambda: str(uuid.uuid4())) diff --git a/hopper/models/ws_dto.py b/hopper/models/ws_dto.py index 40bead7..8eddfe1 100644 --- a/hopper/models/ws_dto.py +++ b/hopper/models/ws_dto.py @@ -1,6 +1,10 @@ from __future__ import annotations +import json +from typing import TypeVar, Generic + from pydantic import Field +from pydantic.generics import GenericModel from hopper.api.dto import BaseModel, BoardDto, DestinationDto, PlayerDto, PositionDto from hopper.enums import ObjectType @@ -15,6 +19,7 @@ class LayerDto(BaseModel): name: str objects: list[LayerObjectDto] + class GameDumpPlayerDto(PlayerDto): ... @@ -24,3 +29,22 @@ class GameDumpDto(BaseModel): destination: DestinationDto players: list[GameDumpPlayerDto] layers: list[LayerDto] + + +TMessageData = TypeVar("TMessageData", bound=BaseModel) + + +class WSMessage(GenericModel): + message: str + data: TMessageData + + def __str__(self) -> str: + return self.to_str() + + def to_str(self) -> str: + return json.dumps(self.dict()) + + +class WSGameDumpMessage(WSMessage): + message: str = "game_dump" + data: GameDumpDto diff --git a/hopper/ws_server.py b/hopper/ws_server.py index 7e0ca99..70e3b08 100644 --- a/hopper/ws_server.py +++ b/hopper/ws_server.py @@ -1,5 +1,4 @@ import asyncio -import json import logging from threading import Thread @@ -7,7 +6,7 @@ import websockets from websockets import WebSocketServerProtocol from websockets.exceptions import ConnectionClosedOK -from hopper.models.ws_dto import GameDumpDto +from hopper.models.ws_dto import GameDumpDto, WSGameDumpMessage from settings import settings @@ -32,7 +31,7 @@ class WSServer(Thread): self.connected_clients.remove(websocket) logging.info(f"Remove client: {websocket.id}") - def _create_game_dump_message(self) -> str: + def _create_game_dump_message(self) -> WSGameDumpMessage: # avoid circular imports from hopper.api.dependencies import get_game_engine @@ -44,7 +43,7 @@ class WSServer(Thread): players=engine.players, layers=engine.get_board_layout().layers, ) - return json.dumps(game_dump.dict()) + return WSGameDumpMessage(data=game_dump) async def send_game_dump_to_client( self, websocket: WebSocketServerProtocol @@ -52,7 +51,7 @@ class WSServer(Thread): """Send game dump to the client""" message = self._create_game_dump_message() logging.debug(f"Sending game dump to client: {websocket.id}") - await websocket.send(message) + await websocket.send(message.to_str()) async def send_game_dump(self) -> None: """Broadcast game state to all connected clients"""