WebSocket Relay¶
Overview¶
The shared session relay server (codemol/share/server.py) is an async WebSocket server that manages rooms, routes messages between hosts and viewers, and handles history replay for late joiners.
Architecture¶
graph TD
H[Host Client] -->|WebSocket| S[Relay Server]
S -->|WebSocket| V1[Viewer 1]
S -->|WebSocket| V2[Viewer 2]
S -->|WebSocket| V3[Viewer 3]
subgraph Room ABC123
H
V1
V2
V3
end
Room Model¶
Rooms are stored as a dictionary on the server:
rooms = {
"ABC123": {
"host": ws_connection, # Host's WebSocket
"viewers": {ws1, ws2, ...}, # Set of viewer WebSockets
"history_pending": [...] # Commands waiting for replay
}
}
Room codes are 6-character uppercase hex strings (e.g., "A1B2C3"), generated randomly on room creation.
Message Types¶
| Type | Direction | Description |
|---|---|---|
create |
Client → Server | Host creates a new room |
join |
Client → Server | Viewer joins by code |
command |
Host → Server → Viewers | Visualization command broadcast |
activate |
Host → Server → Viewers | Structure activation broadcast |
history_request |
Viewer → Server → Host | Request command history |
history |
Host → Server → Viewer | Command history for replay |
close |
Host → Server | Close room, disconnect all viewers |
Message Flow: Room Creation¶
sequenceDiagram
participant Host
participant Server
Host->>Server: {"type": "create"}
Server->>Server: Generate code "ABC123"
Server->>Server: rooms["ABC123"] = {host: ws, viewers: set()}
Server-->>Host: {"type": "created", "code": "ABC123"}
Message Flow: Viewer Join¶
sequenceDiagram
participant Viewer
participant Server
participant Host
Viewer->>Server: {"type": "join", "code": "ABC123"}
Server->>Server: rooms["ABC123"]["viewers"].add(ws)
Server-->>Viewer: {"type": "joined", "code": "ABC123"}
Viewer->>Server: {"type": "history_request"}
Server->>Host: {"type": "history_request"}
Host-->>Server: {"type": "history", "commands": [...]}
Server-->>Viewer: {"type": "history", "commands": [...]}
Message Flow: Command Broadcast¶
sequenceDiagram
participant Host
participant Server
participant V1 as Viewer 1
participant V2 as Viewer 2
Host->>Server: {"type": "command", "data": "/rep cartoon protein"}
Server->>V1: {"type": "command", "data": "/rep cartoon protein"}
Server->>V2: {"type": "command", "data": "/rep cartoon protein"}
Server Entry Point¶
The server uses Python's websockets library:
async def _handler(ws):
"""Handle a single WebSocket connection."""
async for message in ws:
data = json.loads(message)
match data["type"]:
case "create": ...
case "join": ...
case "command": ...
case "close": ...
The server runs as a separate async process, typically on localhost:8765.