From bbfc45925e82c364519b9d796758003365bc9005 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Tue, 11 Aug 2026 22:11:18 +0200 Subject: feat(node): Phase 11 — production-ready daemon with WebRTC, WS, chat, HTTP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The node daemon was previously a skeleton that only started QUIC/TCP servers and the local web UI. All browser-facing functionality (WebRTC, hub WebSocket, chat store, HTTP file API) lived in QE demo scripts. This rewrites daemon.py to be fully self-contained: - WebRTC transport for browser clients (aiortc DataChannel) - Hub WebSocket task (signaling, revocations, WebRTC offers) - ChatStore per group (SQLite in ~/.local/share/meshbay/) - HTTP file API per group (create_http_app on configured port) - Graceful shutdown (all transports, stores, tasks) - hub_client: _ws tracking + send_ws() for chat notifications - config: data_dir field for persistent state - systemd: security hardening (ProtectSystem, StateDirectory) Co-Authored-By: Claude Opus 4.6 --- packages/meshbay-node/src/meshbay_node/hub_client.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'packages/meshbay-node/src/meshbay_node/hub_client.py') diff --git a/packages/meshbay-node/src/meshbay_node/hub_client.py b/packages/meshbay-node/src/meshbay_node/hub_client.py index a9a1d6c..ca0e776 100644 --- a/packages/meshbay-node/src/meshbay_node/hub_client.py +++ b/packages/meshbay-node/src/meshbay_node/hub_client.py @@ -81,6 +81,7 @@ class HubClient: self._keys = keys self._http = httpx.AsyncClient(timeout=15, base_url=config.hub_url) self._session: HubSession | None = None + self._ws: Any = None async def __aenter__(self): return self @@ -246,6 +247,15 @@ class HubClient: # ── Persistent WebSocket (signaling + revocations) ────────────────────── + async def send_ws(self, data: str) -> None: + """Send a message on the hub WebSocket (if connected). Best-effort.""" + ws = self._ws + if ws: + try: + await ws.send(data) + except Exception: + pass + async def maintain_ws( self, on_incoming: Any = None, @@ -282,6 +292,7 @@ class HubClient: log.error("WS auth failed: %s", auth_resp) return + self._ws = ws log.info("Hub WS connected") async for raw in ws: @@ -310,10 +321,13 @@ class HubClient: elif mtype == "pong": pass + except asyncio.CancelledError: + raise except Exception as e: log.warning("Hub WS disconnected: %s — reconnecting in 5s", e) - import asyncio await asyncio.sleep(5) + finally: + self._ws = None # ── Convenience: full startup sequence ─────────────────────────────────── -- cgit v1.2.3