import asyncio import logging import websockets from websockets import WebSocketServerProtocol, broadcast from settings import settings connected_clients = set[WebSocketServerProtocol]() def setup_logging() -> None: logging.basicConfig( level=settings.log_level, format="%(asctime)s %(levelname)s - %(message)s", ) async def ws_handler(websocket: WebSocketServerProtocol): connected_clients.add(websocket) logging.info(f"Add client: {websocket.id}") try: async for message in websocket: logging.debug(f"Received message on {websocket.path}: {message}") broadcast_clients = [client for client in connected_clients if client.id != websocket.id] if broadcast_clients: logging.debug(f"Broadcast message to clients: {broadcast_clients}") broadcast(connected_clients, message) finally: connected_clients.remove(websocket) logging.info(f"Remove client: {websocket.id}") async def main(): setup_logging() logging.info( f"Starting FairHopper Websockets Server on {settings.ws_server.HOST}:{settings.ws_server.PORT}" ) async with websockets.serve( ws_handler=ws_handler, host=settings.ws_server.HOST, port=settings.ws_server.PORT, ): await asyncio.Future() # run forever if __name__ == "__main__": try: asyncio.run(main()) except (KeyboardInterrupt, SystemExit): logging.info(f"FairHopper Websockets Server terminated")