webrtc_signaling_server
WebRTC signaling: peer registry, session/room relay, and secure-mode gates.
Implements the WebSocket signaling plane the WebRTC streaming mode rides on. One in-process "server" peer owns the media graph; browser "client" peers (controllers and viewers, one set per display) pair with it through SESSION messages, or exchange ROOM messages for multi-peer rooms. Newest-connection-wins eviction mirrors websockets mode so a page refresh supersedes its own stale socket, with a takeover-storm breaker so two live auto-reconnecting pages cannot trade the session forever.
Wire protocol (text frames, space-separated): a peer opens with
HELLO <server|client> [<json-metadata>] (client_type, client_slot,
client_strict_viewer, client_token, server_token, display_id,
display_position, fullcolor_codecs: the codec names the client decodes at
4:4:4, tenbit_codecs: the formats it decodes at 10 bits, a codec name for 4:2:0
and the name with 444 after it for 4:4:4, client_tab_id, cc_start_kbps: the rate congestion control last held
the page's display at, page_size: the [width, height] its first resize will ask for, resume_key: a secret of
the page's session) and is answered HELLO. A server that does not know a key ignores it. A client whose
socket was cut with no close frame keeps its session for SESSION_HOLD_S: a hello naming its resume_key is
answered RESUMED <callee-id> and carries on that session, under its old peer id, with what was addressed to it
meanwhile; the media path never needed the socket. SESSION <peer-id|server> pairs
the caller with the callee: the caller gets SESSION_OK <callee-id>, the callee
SESSION_START <caller-id> <client_type> <display_id> <display_position> [<client_token>] [fullcolor=<codec,...>] [tenbit=<format,...>], and a disconnect sends the partner SESSION_END <peer-id> <client_type>. In a session every message is addressed <peer-id> <message>
and relayed as <sender-id> <message>, only between session partners. ROOM <room-id> joins or creates a room (ROOM_OK <member-ids>, members get
ROOM_PEER_JOINED / ROOM_PEER_LEFT <peer-id>), where ROOM_PEER_MSG <peer-id> <message> is relayed as ROOM_PEER_MSG <sender-id> <message>.
Errors are ERROR <text>.
Concurrency model: all registry mutation happens under a single asyncio.Lock, and every socket send/close triggered while holding it is deferred and flushed after release, so one slow peer socket can never serialize other handshakes.
In secure mode (a master token is configured) the auth middleware forwards
WebSocket upgrades without Basic auth, so the token checks here are the only
gate: client peers must present a provisioned session token and server peers
the master token itself. Token checks are constant-time lookups in the live
control-plane table (/api/tokens), read per handshake.
attributeSERVER_PEER_SECRET= secrets.token_urlsafe(32)attributelogger= logging.getLogger('signaling')attributeSESSION_HOLD_S= 3.0attributeHELD_LINES_MAX= 256attributeMAX_PAGE_SIZE= 8192attributeHELLO_MAX_BYTES= 16 * 1024attributeDISPLAY_ID_RE= re.compile('[A-Za-z0-9_-]{1,32}')