4.6 KiB
4.6 KiB
WebSocket Event Flow - Jackbox Integration
Event Broadcasting Behavior
| Event | Broadcast To | Requires Subscription? |
|---|---|---|
session.started |
All authenticated clients | ❌ NO |
game.added |
Session subscribers only | ✅ YES |
session.ended |
Session subscribers only | ✅ YES |
Bot Connection Flow
1. Connect to WebSocket
↓
2. Send auth message with JWT token
↓
3. Receive auth_success
↓
4. Wait for session.started (automatic broadcast)
↓
5. When session.started received:
- Subscribe to that specific session ID
- Announce "Game Night is starting!"
↓
6. Receive game.added events (for subscribed session)
- Announce new games
↓
7. Receive session.ended event (for subscribed session)
- Announce final votes + goodnight
Message Formats
1. Authentication
Bot → Server:
{
"type": "auth",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Server → Bot:
{
"type": "auth_success",
"message": "Authenticated successfully"
}
2. Session Started (Automatic Broadcast)
Server → Bot:
{
"type": "session.started",
"timestamp": "2025-11-01T03:24:30Z",
"data": {
"session": {
"id": 21,
"is_active": 1,
"created_at": "2025-11-01 07:24:30",
"notes": null
}
}
}
Bot Action:
- Automatically subscribe to this session
- Announce "🎮 Game Night is starting! Session #21"
3. Subscribe to Session
Bot → Server:
{
"type": "subscribe",
"sessionId": 21
}
Server → Bot:
{
"type": "subscribed",
"message": "Subscribed to session 21"
}
4. Game Added (Requires Subscription)
Server → Bot:
{
"type": "game.added",
"timestamp": "2025-11-01T03:25:00Z",
"data": {
"session": {
"id": 21,
"is_active": true,
"games_played": 1
},
"game": {
"id": 42,
"title": "Drawful 2",
"pack_name": "Drawful 2",
"min_players": 3,
"max_players": 8,
"manually_added": false
}
}
}
Bot Action:
- Announce previous game's votes (if any)
- Announce "🎮 Coming up next: Drawful 2!"
5. Session Ended (Requires Subscription)
Server → Bot:
{
"type": "session.ended",
"timestamp": "2025-11-01T04:30:00Z",
"data": {
"session": {
"id": 21,
"is_active": 0,
"games_played": 5
}
}
}
Bot Action:
- Announce final game's votes (if any)
- Announce "🌙 Game Night has ended! Thanks for playing!"
- Clear active session (reset to time-based vote debouncing)
Fallback Polling
If WebSocket events are missed, the bot has a fallback polling mechanism (every 30 seconds):
- Detects new sessions via HTTP GET
/api/sessions/active - Detects ended sessions when active session becomes null/inactive
- Logs warnings when polling detects changes (indicates missed WebSocket events)
Example warning logs:
WARN Found active session 21 via polling (session.started event may have been missed)
WARN Active session ended (detected via polling, session.ended event may have been missed)
Testing
Expected Logs (Happy Path)
INFO Authentication successful
INFO Session started: ID=21
INFO Subscribed to session 21
INFO Active session set to 21
INFO Broadcasting Jackbox message: 🎮 Game Night is starting! Session #21
INFO Subscription confirmed: Subscribed to session 21
INFO Game added: Drawful 2 from Drawful 2
INFO Broadcasting Jackbox message: 🎮 Coming up next: Drawful 2!
INFO Session ended event received
INFO Broadcasting Jackbox message: 🌙 Game Night has ended! Thanks for playing!
Expected Logs (Fallback Polling)
INFO Authentication successful
WARN Found active session 21 via polling (session.started event may have been missed), subscribing...
INFO Subscribed to session 21
Troubleshooting
Bot doesn't receive session.started
- Check backend logs: Should say "Broadcasted session.started to X client(s)"
- Check bot is authenticated: Look for "Authentication successful" in logs
- Check WebSocket connection: Should say "WebSocket connected"
Bot doesn't receive game.added or session.ended
- Check bot subscribed to session: Look for "Subscribed to session X" in logs
- Check backend logs: Should say "Broadcasted game.added to X client(s) for session Y"
- If X = 0, bot didn't subscribe properly
Polling warnings appear
- This means WebSocket events aren't being received
- Check your backend is calling
broadcastToAll()forsession.started - Check your backend is calling
broadcastEvent(sessionId)forgame.addedandsession.ended