Replace existing docs with fresh documentation built entirely from source code analysis. OpenAPI 3.1 spec as source of truth, plus human-readable Markdown with curl examples, response samples, and workflow guides. - OpenAPI 3.1 spec covering all 42 endpoints (validated against source) - 7 endpoint reference docs (auth, games, sessions, picker, stats, votes, webhooks) - WebSocket protocol documentation (auth, subscriptions, 4 event types) - 4 guide documents (getting started, session lifecycle, voting, webhooks) - API README with overview, auth docs, and quick reference table - Old docs archived to docs/archive/ Made-with: Cursor
311 lines
8.0 KiB
Markdown
311 lines
8.0 KiB
Markdown
# WebSocket Subscription Guide
|
|
|
|
## 📋 Overview
|
|
|
|
This guide explains how WebSocket subscriptions work in the Jackbox Game Picker and which events require subscriptions.
|
|
|
|
## 🔌 Connection & Authentication
|
|
|
|
### 1. Connect to WebSocket
|
|
|
|
```javascript
|
|
const ws = new WebSocket('ws://localhost:5000/api/sessions/live');
|
|
```
|
|
|
|
### 2. Authenticate
|
|
|
|
```javascript
|
|
ws.send(JSON.stringify({
|
|
type: 'auth',
|
|
token: 'YOUR_JWT_TOKEN'
|
|
}));
|
|
```
|
|
|
|
### 3. Wait for Auth Success
|
|
|
|
```javascript
|
|
ws.on('message', (data) => {
|
|
const msg = JSON.parse(data.toString());
|
|
if (msg.type === 'auth_success') {
|
|
console.log('Authenticated!');
|
|
// Now you can subscribe to sessions
|
|
}
|
|
});
|
|
```
|
|
|
|
## 📨 Event Types & Subscription Requirements
|
|
|
|
| Event Type | Requires Subscription? | Broadcast To | When to Subscribe |
|
|
|------------|------------------------|--------------|-------------------|
|
|
| `session.started` | ❌ **NO** | All authenticated clients | N/A - Automatic |
|
|
| `game.added` | ✅ **YES** | Subscribed clients only | After session.started |
|
|
| `vote.received` | ✅ **YES** | Subscribed clients only | After session.started |
|
|
| `session.ended` | ✅ **YES** | Subscribed clients only | After session.started |
|
|
|
|
## 🎯 Subscription Strategy
|
|
|
|
### Strategy 1: Auto-Subscribe to New Sessions (Recommended for Bots)
|
|
|
|
```javascript
|
|
ws.on('message', (data) => {
|
|
const msg = JSON.parse(data.toString());
|
|
|
|
// After authentication
|
|
if (msg.type === 'auth_success') {
|
|
console.log('✅ Authenticated');
|
|
}
|
|
|
|
// Auto-subscribe to new sessions
|
|
if (msg.type === 'session.started') {
|
|
const sessionId = msg.data.session.id;
|
|
console.log(`🎮 New session ${sessionId} started!`);
|
|
|
|
// Subscribe to this session
|
|
ws.send(JSON.stringify({
|
|
type: 'subscribe',
|
|
sessionId: sessionId
|
|
}));
|
|
}
|
|
|
|
// Now you'll receive game.added, vote.received, and session.ended
|
|
if (msg.type === 'game.added') {
|
|
console.log(`🎲 Game: ${msg.data.game.title}`);
|
|
}
|
|
|
|
if (msg.type === 'session.ended') {
|
|
console.log(`🌙 Session ended! ${msg.data.session.games_played} games played`);
|
|
}
|
|
});
|
|
```
|
|
|
|
### Strategy 2: Subscribe to Active Session on Connect
|
|
|
|
```javascript
|
|
ws.on('message', (data) => {
|
|
const msg = JSON.parse(data.toString());
|
|
|
|
if (msg.type === 'auth_success') {
|
|
console.log('✅ Authenticated');
|
|
|
|
// Fetch active session from API
|
|
fetch('http://localhost:5000/api/sessions/active')
|
|
.then(res => res.json())
|
|
.then(session => {
|
|
if (session && session.id) {
|
|
// Subscribe to active session
|
|
ws.send(JSON.stringify({
|
|
type: 'subscribe',
|
|
sessionId: session.id
|
|
}));
|
|
}
|
|
});
|
|
}
|
|
});
|
|
```
|
|
|
|
### Strategy 3: Subscribe to Specific Session
|
|
|
|
```javascript
|
|
ws.on('message', (data) => {
|
|
const msg = JSON.parse(data.toString());
|
|
|
|
if (msg.type === 'auth_success') {
|
|
console.log('✅ Authenticated');
|
|
|
|
// Subscribe to specific session
|
|
const sessionId = 17;
|
|
ws.send(JSON.stringify({
|
|
type: 'subscribe',
|
|
sessionId: sessionId
|
|
}));
|
|
}
|
|
|
|
if (msg.type === 'subscribed') {
|
|
console.log(`✅ Subscribed to session ${msg.sessionId}`);
|
|
}
|
|
});
|
|
```
|
|
|
|
## 🔄 Complete Bot Flow
|
|
|
|
```javascript
|
|
const WebSocket = require('ws');
|
|
|
|
class JackboxBot {
|
|
constructor(token) {
|
|
this.token = token;
|
|
this.ws = null;
|
|
this.currentSessionId = null;
|
|
}
|
|
|
|
connect() {
|
|
this.ws = new WebSocket('ws://localhost:5000/api/sessions/live');
|
|
|
|
this.ws.on('open', () => {
|
|
console.log('🔌 Connected to WebSocket');
|
|
this.authenticate();
|
|
});
|
|
|
|
this.ws.on('message', (data) => {
|
|
this.handleMessage(JSON.parse(data.toString()));
|
|
});
|
|
}
|
|
|
|
authenticate() {
|
|
this.ws.send(JSON.stringify({
|
|
type: 'auth',
|
|
token: this.token
|
|
}));
|
|
}
|
|
|
|
handleMessage(msg) {
|
|
switch (msg.type) {
|
|
case 'auth_success':
|
|
console.log('✅ Authenticated');
|
|
// Don't subscribe yet - wait for session.started
|
|
break;
|
|
|
|
case 'session.started':
|
|
this.currentSessionId = msg.data.session.id;
|
|
console.log(`🎮 Session ${this.currentSessionId} started!`);
|
|
|
|
// Auto-subscribe to this session
|
|
this.ws.send(JSON.stringify({
|
|
type: 'subscribe',
|
|
sessionId: this.currentSessionId
|
|
}));
|
|
|
|
// Announce to users
|
|
this.announce(`Game Night has started! Session #${this.currentSessionId}`);
|
|
break;
|
|
|
|
case 'subscribed':
|
|
console.log(`✅ Subscribed to session ${msg.sessionId}`);
|
|
break;
|
|
|
|
case 'game.added':
|
|
console.log(`🎲 Game: ${msg.data.game.title}`);
|
|
this.announce(`Now playing: ${msg.data.game.title}`);
|
|
break;
|
|
|
|
case 'vote.received':
|
|
console.log(`🗳️ Vote: ${msg.data.vote.type}`);
|
|
break;
|
|
|
|
case 'session.ended':
|
|
console.log(`🌙 Session ${msg.data.session.id} ended`);
|
|
this.announce(`Game Night ended! ${msg.data.session.games_played} games played`);
|
|
this.currentSessionId = null;
|
|
break;
|
|
}
|
|
}
|
|
|
|
announce(message) {
|
|
// Send to IRC/Discord/Kosmi/etc
|
|
console.log(`📢 ${message}`);
|
|
}
|
|
}
|
|
|
|
// Usage
|
|
const bot = new JackboxBot('YOUR_JWT_TOKEN');
|
|
bot.connect();
|
|
```
|
|
|
|
## 📊 Subscription Lifecycle
|
|
|
|
```
|
|
1. Connect to WebSocket
|
|
↓
|
|
2. Send auth message
|
|
↓
|
|
3. Receive auth_success
|
|
↓
|
|
4. Wait for session.started (no subscription needed)
|
|
↓
|
|
5. Receive session.started
|
|
↓
|
|
6. Send subscribe message with sessionId
|
|
↓
|
|
7. Receive subscribed confirmation
|
|
↓
|
|
8. Now receive: game.added, vote.received, session.ended
|
|
↓
|
|
9. Receive session.ended
|
|
↓
|
|
10. Wait for next session.started (repeat from step 4)
|
|
```
|
|
|
|
## 🔍 Debugging
|
|
|
|
### Check What You're Subscribed To
|
|
|
|
The WebSocket manager tracks subscriptions. Check backend logs:
|
|
|
|
```
|
|
[WebSocket] Client subscribed to session 17
|
|
[WebSocket] Client unsubscribed from session 17
|
|
```
|
|
|
|
### Verify Event Reception
|
|
|
|
**session.started** - Should receive immediately after authentication (no subscription needed):
|
|
```
|
|
[WebSocket] Broadcasted session.started to 2 authenticated client(s)
|
|
```
|
|
|
|
**game.added, vote.received, session.ended** - Only after subscribing:
|
|
```
|
|
[WebSocket] Broadcasted game.added to 1 client(s) for session 17
|
|
```
|
|
|
|
### Common Issues
|
|
|
|
1. **Not receiving session.started:**
|
|
- ✅ Are you authenticated?
|
|
- ✅ Is your WebSocket connection open?
|
|
- ✅ Check backend logs for broadcast confirmation
|
|
|
|
2. **Not receiving game.added:**
|
|
- ✅ Did you subscribe to the session?
|
|
- ✅ Did you receive `subscribed` confirmation?
|
|
- ✅ Is the session ID correct?
|
|
|
|
3. **Not receiving session.ended:**
|
|
- ✅ Are you still subscribed to the session?
|
|
- ✅ Did the session actually close?
|
|
- ✅ Check backend logs
|
|
|
|
## 🎯 Best Practices
|
|
|
|
1. **Auto-subscribe to new sessions** when you receive `session.started`
|
|
2. **Don't subscribe before session.started** - there's nothing to subscribe to yet
|
|
3. **Handle reconnections** - re-authenticate and re-subscribe on reconnect
|
|
4. **Use polling as fallback** - poll `/api/sessions/active` every 30s as backup
|
|
5. **Unsubscribe when done** - clean up subscriptions when you're done with a session
|
|
6. **Validate session IDs** - make sure the session exists before subscribing
|
|
|
|
## 📝 Summary
|
|
|
|
### ❌ No Subscription Required
|
|
- `session.started` - Broadcast to **all authenticated clients**
|
|
|
|
### ✅ Subscription Required
|
|
- `game.added` - Only to **subscribed clients**
|
|
- `vote.received` - Only to **subscribed clients**
|
|
- `session.ended` - Only to **subscribed clients**
|
|
|
|
### 🎯 Recommended Flow
|
|
1. Authenticate
|
|
2. Wait for `session.started` (automatic)
|
|
3. Subscribe to the session
|
|
4. Receive `game.added`, `vote.received`, `session.ended`
|
|
5. Repeat from step 2 for next session
|
|
|
|
## 🔗 Related Documentation
|
|
|
|
- [SESSION_START_WEBSOCKET.md](SESSION_START_WEBSOCKET.md) - session.started event details
|
|
- [SESSION_END_WEBSOCKET.md](SESSION_END_WEBSOCKET.md) - session.ended event details
|
|
- [API_QUICK_REFERENCE.md](API_QUICK_REFERENCE.md) - API reference
|
|
- [BOT_INTEGRATION.md](BOT_INTEGRATION.md) - Bot integration guide
|
|
|