diff --git a/Makefile b/Makefile index 4e9d471..928b62b 100644 --- a/Makefile +++ b/Makefile @@ -14,3 +14,7 @@ run-dev: --port 8010 \ --workers=1 \ --reload + +run-ws: + @poetry run \ + python ws_server.py diff --git a/hopper/models/config.py b/hopper/models/config.py index 2e10d00..284bcde 100644 --- a/hopper/models/config.py +++ b/hopper/models/config.py @@ -16,6 +16,12 @@ class InactivityWatchdogSettings: TICK_INTERVAL: int = 1 # seconds +@dataclass +class WSServerSettings: + HOST: str = "localhost" + PORT: int = 8010 + + @dataclass class DebugSettings: PRINT_BOARD: bool = False @@ -26,4 +32,5 @@ class DebugSettings: class Settings: board: BoardSettings inacivity_watchdog: InactivityWatchdogSettings + ws_server: WSServerSettings debug: Optional[DebugSettings] = None diff --git a/settings_template.py b/settings_template.py index a786306..b865ebb 100644 --- a/settings_template.py +++ b/settings_template.py @@ -1,7 +1,13 @@ -from hopper.models.config import BoardSettings, InactivityWatchdogSettings, Settings +from hopper.models.config import ( + BoardSettings, + InactivityWatchdogSettings, + Settings, + WSServerSettings, +) settings = Settings( board=BoardSettings(), inacivity_watchdog=InactivityWatchdogSettings(), + ws_server=WSServerSettings(), debug=None, ) diff --git a/ws_server.py b/ws_server.py new file mode 100644 index 0000000..abd123e --- /dev/null +++ b/ws_server.py @@ -0,0 +1,51 @@ +import asyncio +import logging + +import websockets +from websockets import WebSocketServerProtocol, broadcast + +from settings import settings + +connected_clients = set() + + +def setup_logging() -> None: + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s - %(message)s", + ) + + +async def ws_handler(websocket: WebSocketServerProtocol): + connected_clients.add(websocket) + logging.info(f"Add client: {websocket}") + + try: + async for message in websocket: + broadcast(connected_clients, message) + # await websocket.send(f"Are you talking to me? {message}") + finally: + connected_clients.remove(websocket) + logging.info(f"Remove client: {websocket}") + + +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")