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"""