#!/usr/bin/env python3 """ Minimal signalling relay for WebRTC data‑channel projects. Contract: • Client sends {"type":"register","id": "..."} once on connect. • Later it sends {"type":"signal","from": "...", "target": "...", "data": {...}} The server forwards that JSON verbatim to the socket whose id == target. """ import asyncio, json, logging import websockets logging.basicConfig(level=logging.INFO) CLIENTS: dict[str, websockets.WebSocketServerProtocol] = {} async def handler(ws: websockets.WebSocketServerProtocol): peer_id = None try: async for raw in ws: try: msg = json.loads(raw) except json.JSONDecodeError: logging.warning("Bad JSON from %s: %s", peer_id, raw) continue mtype = msg.get("type") if mtype == "register": peer_id = msg.get("id") if not peer_id: await ws.close(code=4000, reason="Missing id") return CLIENTS[peer_id] = ws logging.info("Registered %s (%d clients)", peer_id, len(CLIENTS)) elif mtype == "signal": target = msg.get("target") if not target: continue dest = CLIENTS.get(target) if dest: await dest.send(raw) # relay as‑is logging.debug("Relayed %s → %s", peer_id, target) else: logging.warning("Target %s not found", target) except websockets.ConnectionClosed: pass finally: # tidy up on disconnect if peer_id and CLIENTS.get(peer_id) is ws: CLIENTS.pop(peer_id) logging.info("Disconnected %s (%d clients left)", peer_id, len(CLIENTS)) async def main(): async with websockets.serve(handler, host="0.0.0.0", port=8080): logging.info("Signalling server listening on :8080") await asyncio.Future() # run forever if __name__ == "__main__": asyncio.run(main())