Integrated WS server
This commit is contained in:
73
hopper/ws_server.py
Normal file
73
hopper/ws_server.py
Normal file
@ -0,0 +1,73 @@
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
from threading import Thread
|
||||
|
||||
import websockets
|
||||
from websockets import WebSocketServerProtocol
|
||||
|
||||
from hopper.models.ws_dto import GameStateDto
|
||||
from settings import settings
|
||||
|
||||
|
||||
class WSServer(Thread):
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
self.connected_clients = set[WebSocketServerProtocol]()
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
async def ws_handler(self, websocket: WebSocketServerProtocol) -> None:
|
||||
self.connected_clients.add(websocket)
|
||||
logging.info(f"Add client: {websocket.id}")
|
||||
|
||||
try:
|
||||
await self.send_game_state_to_client(websocket)
|
||||
finally:
|
||||
self.connected_clients.remove(websocket)
|
||||
logging.info(f"Remove client: {websocket.id}")
|
||||
|
||||
def _create_game_state_message(self) -> str:
|
||||
# avoid circular imports
|
||||
from hopper.api.dependencies import get_game_engine
|
||||
|
||||
engine = get_game_engine()
|
||||
|
||||
game_state = GameStateDto(
|
||||
board=engine.board,
|
||||
destination=engine.board.destination,
|
||||
players=engine.players,
|
||||
layers=engine.get_board_layout().layers,
|
||||
)
|
||||
return json.dumps(game_state.dict())
|
||||
|
||||
async def send_game_state_to_client(
|
||||
self, websocket: WebSocketServerProtocol
|
||||
) -> None:
|
||||
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:
|
||||
if not self.connected_clients:
|
||||
return
|
||||
|
||||
message = self._create_game_state_message()
|
||||
logging.debug(
|
||||
f"Sending game state to clients: {self.connected_clients}: {message}"
|
||||
)
|
||||
for client in self.connected_clients:
|
||||
await client.send(message)
|
||||
|
||||
async def run_async(self) -> None:
|
||||
logging.info(
|
||||
f"Starting FairHopper Websockets Server on {settings.ws_server.HOST}:{settings.ws_server.PORT}"
|
||||
)
|
||||
|
||||
async with websockets.serve(
|
||||
ws_handler=self.ws_handler,
|
||||
host=settings.ws_server.HOST,
|
||||
port=settings.ws_server.PORT,
|
||||
):
|
||||
await asyncio.Future() # run forever
|
||||
|
||||
def run(self) -> None:
|
||||
asyncio.run(self.run_async())
|
||||
Reference in New Issue
Block a user