Skip to content

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.