Real-time updates¶
Pollux uses WebSockets to push vote results and quiz events to all connected clients in real time.
How it works¶
When a client connects to a WebSocket endpoint, the server:
- Validates the UUID and optional user ID
- Upgrades the HTTP connection to a WebSocket
- Subscribes the client to a channel named after the poll UUID
- Sends the current state (existing results, active question, etc.)
- Listens for future broadcasts on that channel
Pub/sub model¶
Pollux uses Bun's built-in server.publish() / ws.subscribe() mechanism:
flowchart LR
A["Client A"] -->|"WebSocket"| B["Server"]
C["Client B"] -->|"WebSocket"| B
B --> D["Channel: poll-uuid"]
B -->|"publish()"| D
D --> A
D --> C
E["Vote / Quiz Event"] --> B
When a vote is cast, the handler:
1. Stores the vote in SQLite
2. Calls srv.publish(uuid, JSON.stringify({ result: ... }))
3. All WebSocket clients subscribed to that channel receive the message
One handler, four kinds¶
There is a single websocket handler in ws.ts. It serves every mode,
discriminated by ws.data.kind, which is stamped on the socket during the
upgrade. The kind selects the channel prefix and the shape of the state sent
on open.
flowchart TD
U["WS upgrade"] --> K{"ws.data.kind"}
K -->|static| S["channel: uuid"]
K -->|dynamic| D["channel: dynamic:uuid"]
K -->|quizz| Q["channel: quizz:uuid"]
K -->|raffle| R["channel: raffle:uuid"]
S --> O["subscribe + send current state"]
D --> O
Q --> O
R --> O
Channel naming¶
| Poll type | Channel pattern |
|---|---|
| Static poll | {uuid} |
| Dynamic poll | dynamic:{uuid} |
| Quiz | quizz:{uuid} |
| Raffle | raffle:{uuid} |
This separation prevents static poll clients from receiving dynamic poll events and vice versa.
WebSocket endpoints¶
| Endpoint | Poll type |
|---|---|
/ws?uuid=UUID |
Static polls |
/ws/dynamic?uuid=UUID |
Dynamic polls |
/ws/quizz?uuid=UUID&user=USER_ID |
Quizzes |
/ws/raffle?uuid=UUID |
Raffles |
Reconnection¶
The quiz result page implements automatic reconnection: when the WebSocket closes, it attempts to reconnect after 2 seconds.
On reconnection, the server sends the current state in the open handler, so the client catches up with any missed events.