diff --git a/cah/constructors.py b/cah/constructors.py index 8511acd..dfb8ca7 100644 --- a/cah/constructors.py +++ b/cah/constructors.py @@ -5,8 +5,35 @@ class CAHClient: resource: str, platform: str, csid: str, - connected_at: int): + connected_at: int, + current_game: str | None): self.resource: str = resource self.platform: str = platform self.csid: str = csid - self.connected_at: int = connected_at \ No newline at end of file + self.connected_at: int = connected_at + self.current_game: str | None = current_game + + def __iter__(self): + return [value for value in self.__dict__.values() if isinstance(value, int) or isinstance(value, float)].__iter__() + +class CAHGame: + + def __init__(self, + id: str, + rounds: int, + players: list[dict], + created_at: int, + state: int, + started_at: int, + state_changed_at: int, + ): + self.id: str = id + self.rounds: int = rounds + self.players: list[dict] = players + self.created_at: int = created_at + self.state: int = state + self.started_at: int = started_at + self.state_changed_at: int = state_changed_at + + def __iter__(self): + return [value for value in self.__dict__.values() if isinstance(value, int) or isinstance(value, float)].__iter__() \ No newline at end of file diff --git a/cah/websocket_conn.py b/cah/websocket_conn.py index 99172c9..02b89ee 100644 --- a/cah/websocket_conn.py +++ b/cah/websocket_conn.py @@ -17,6 +17,36 @@ class ConnectionManager: for connection in self.active_connections: if connection.get('csid') == csid: return connection + + async def send_client_and_game_lists(self, state, websocket: WebSocket): + clients = [] + games = [game for game in state.games] + + for ws, client in self.active_connections.items(): + print(f"Client: {client}") + _client = client.get('client') + clients.append({ + 'resource': _client.resource, + 'platform': _client.platform, + 'connected_at': _client.connected_at, + 'current_game': _client.current_game.id if _client.current_game else None, + }) + + await websocket.send_json({ + "event": "client_list", + "ts": int(time.time()), + "data": { + "clients": clients + } + }) + await websocket.send_json({ + "event": "game_list", + "ts": int(time.time()), + "data": + { + "games": [str(game.id) for game in games], + } + }) async def connect(self, websocket: WebSocket): await websocket.accept() @@ -27,22 +57,28 @@ class ConnectionManager: async def handshake_complete(self, - websocket: WebSocket, - csid: str, - handshakedClient: CAHClient): - self.active_connections[websocket] = { - 'websocket': websocket, - 'csid': csid, - 'client': handshakedClient, - } - - await self.broadcast({ - "event": "client_connected", - "ts": int(time.time()), - "data": { - "connected_resource": handshakedClient.resource, - } - }) + state, + websocket: WebSocket, + csid: str, + handshakedClient: CAHClient): + + self.active_connections[websocket] = { + 'websocket': websocket, + 'csid': csid, + 'client': handshakedClient, + } + + await self.broadcast({ + "event": "client_connected", + "ts": int(time.time()), + "data": { + "connected_resource": handshakedClient.resource, + "connected_platform": handshakedClient.platform, + } + }) + + await self.send_client_and_game_lists(state, + websocket) def disconnect(self, websocket: WebSocket, csid: str = None): self.active_connections.pop(websocket) diff --git a/endpoints/cah.py b/endpoints/cah.py index df4a874..1ae1865 100644 --- a/endpoints/cah.py +++ b/endpoints/cah.py @@ -5,7 +5,7 @@ import time import uuid import json import random -from cah.constructors import CAHClient +from cah.constructors import CAHClient, CAHGame from cah.websocket_conn import ConnectionManager class CAH(FastAPI): @@ -15,6 +15,7 @@ class CAH(FastAPI): self.util = util self.constants = constants self.glob_state = glob_state + self.games: list[dict] = [] self.ws_endpoints = { "cah": self.cah_handler, @@ -46,16 +47,29 @@ class CAH(FastAPI): try: while True: data = await websocket.receive_json() - if data.get('event') == 'handshake': - await self.cah_handshake(websocket, - data) - else: - sender = self.connection_manager.get_connection_by_ws(websocket) - await self.connection_manager.broadcast({ - "event": "echo", - "from": sender.get('client').resource, - "data": data, + event = data.get('event') + if not event: + await websocket.send_json({ + 'err': True, + 'errorText': 'Invalid data received, closing connection.' }) + return await websocket.close() + print(f"Event: {event}") + match event: + case 'handshake': + await self.cah_handshake(websocket, + data) + case 'create_game': + await self.create_game(websocket, + data) + case _: + sender = self.connection_manager.get_connection_by_ws(websocket) + await self.connection_manager.broadcast({ + "event": "echo", + "ts": int(time.time()), + "from": sender.get('client').resource, + "data": data, + }) except WebSocketDisconnect: disconnected = self.connection_manager.get_connection_by_ws(websocket) self.connection_manager.disconnect(websocket) @@ -71,7 +85,6 @@ class CAH(FastAPI): async def cah_handshake(self, websocket: WebSocket, data): """Handshake""" - self.connection_manager.connect(websocket) data = data.get('data') if not data: await websocket.send_json({ @@ -93,9 +106,10 @@ class CAH(FastAPI): resource=resource, platform=platform, csid=csid, - connected_at=time.time(), # fix + connected_at=int(time.time()), + current_game=None, ) - await self.connection_manager.handshake_complete(websocket, csid, client) + await self.connection_manager.handshake_complete(self, websocket, csid, client) await websocket.send_json({ "event": "handshake_response", @@ -104,6 +118,39 @@ class CAH(FastAPI): "success": True, "resource": resource, "platform": platform, - "games": [str(uuid.uuid4()) for x in range(0, 11)], + "games": [str(game.id) for game in self.games], }, }) + + async def create_game(self, websocket, data: str): + data = data.get('data') + if not data.get('rounds') or not str(data.get('rounds')).isnumeric(): + return await websocket.send_json({ + "event": "create_game_response", + "ts": int(time.time()), + "data": { + "success": False, + "errorText": "Invalid data", + "recvdData": data, + } + }) + client = self.connection_manager.get_connection_by_ws(websocket).get('client') + rounds = int(data.get('rounds')) + game_uuid = str(uuid.uuid4()) + game = CAHGame(id=game_uuid, + rounds=rounds, + players=[client,], + created_at=int(time.time()), + state=-1, + started_at=0, + state_changed_at=int(time.time())) + self.games.append(game) + client.current_game = game + await websocket.send_json({ + "event": "create_game_response", + "ts": int(time.time()), + "data": { + "success": True, + "createdGame": client.current_game.id, + } + })