# Session End WebSocket Event This document describes the `session.ended` WebSocket event that is broadcast when a game session is closed. ## ๐Ÿ“‹ Event Overview When a session is closed (either manually or through timeout), the backend broadcasts a `session.ended` event to all subscribed WebSocket clients. This allows bots and other integrations to react immediately to session closures. ## ๐Ÿ”Œ WebSocket Connection **Endpoint:** `ws://localhost:5000/api/sessions/live` **Authentication:** Required (JWT token) ## ๐Ÿ“จ Event Format ### Event Type ``` session.ended ``` ### Full Message Structure ```json { "type": "session.ended", "timestamp": "2025-11-01T02:30:45.123Z", "data": { "session": { "id": 17, "is_active": 0, "games_played": 5 } } } ``` ### Field Descriptions | Field | Type | Description | |-------|------|-------------| | `type` | string | Always `"session.ended"` | | `timestamp` | string | ISO 8601 timestamp when the event was generated | | `data.session.id` | number | The ID of the session that ended | | `data.session.is_active` | number | Always `0` (inactive) for ended sessions | | `data.session.games_played` | number | Total number of games played in the session | ## ๐Ÿš€ Implementation ### Backend Implementation The `session.ended` event is automatically broadcast when: 1. **Manual Session Close**: Admin closes a session via `POST /api/sessions/:id/close` 2. **Session Timeout**: (If implemented) When a session times out **Code Location:** `backend/routes/sessions.js` - `POST /:id/close` endpoint ```javascript // Broadcast session.ended event via WebSocket const wsManager = getWebSocketManager(); if (wsManager) { const eventData = { session: { id: closedSession.id, is_active: 0, games_played: closedSession.games_played } }; wsManager.broadcastEvent('session.ended', eventData, parseInt(req.params.id)); } ``` ### Client Implementation Example #### Node.js with `ws` library ```javascript const WebSocket = require('ws'); const ws = new WebSocket('ws://localhost:5000/api/sessions/live'); ws.on('open', () => { // Authenticate ws.send(JSON.stringify({ type: 'auth', token: 'your-jwt-token' })); }); ws.on('message', (data) => { const message = JSON.parse(data.toString()); switch (message.type) { case 'auth_success': // Subscribe to session ws.send(JSON.stringify({ type: 'subscribe', sessionId: 17 })); break; case 'session.ended': console.log('Session ended!'); console.log(`Session ID: ${message.data.session.id}`); console.log(`Games played: ${message.data.session.games_played}`); // Handle session end (e.g., announce in IRC, Discord, etc.) break; } }); ``` #### Python with `websockets` library ```python import asyncio import json import websockets async def listen_for_session_end(): uri = "ws://localhost:5000/api/sessions/live" async with websockets.connect(uri) as websocket: # Authenticate await websocket.send(json.dumps({ "type": "auth", "token": "your-jwt-token" })) async for message in websocket: data = json.loads(message) if data["type"] == "auth_success": # Subscribe to session await websocket.send(json.dumps({ "type": "subscribe", "sessionId": 17 })) elif data["type"] == "session.ended": session = data["data"]["session"] print(f"Session {session['id']} ended!") print(f"Games played: {session['games_played']}") # Handle session end asyncio.run(listen_for_session_end()) ``` ## ๐Ÿงช Testing ### Using the Test Script A test script is provided to verify the `session.ended` event: ```bash node test-session-end-websocket.js ``` **Example:** ```bash node test-session-end-websocket.js 17 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` ### Manual Testing Steps 1. **Start the backend server:** ```bash cd backend npm start ``` 2. **Run the test script in another terminal:** ```bash node test-session-end-websocket.js 17 ``` 3. **Close the session in the Picker UI** or via API: ```bash curl -X POST http://localhost:5000/api/sessions/17/close \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" ``` 4. **Verify the event is received** in the test script output ### Expected Output ``` ๐Ÿš€ Testing session.ended WebSocket event โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” ๐Ÿ“ก Connecting to: ws://localhost:5000/api/sessions/live ๐ŸŽฎ Session ID: 17 โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” โœ… Connected to WebSocket server ๐Ÿ” Authenticating... โœ… Authentication successful ๐Ÿ“ป Subscribing to session 17... โœ… Subscribed to session 17 ๐Ÿ‘‚ Listening for session.ended events... (Close the session in the Picker to trigger the event) โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” ๐ŸŽ‰ SESSION.ENDED EVENT RECEIVED! โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” ๐Ÿ“ฆ Event Data: { "type": "session.ended", "timestamp": "2025-11-01T02:30:45.123Z", "data": { "session": { "id": 17, "is_active": 0, "games_played": 5 } } } โœจ Event Details: Session ID: 17 Active: No Games Played: 5 Timestamp: 2025-11-01T02:30:45.123Z โœ… Test successful! The bot should now announce the session end. ``` ## ๐Ÿค– Bot Integration ### IRC/Kosmi Bot Example When the bot receives a `session.ended` event, it should: 1. **Announce the final vote counts** for the last game played 2. **Announce that the game night has ended** 3. **Optionally display session statistics** Example bot response: ``` ๐Ÿ—ณ๏ธ Final votes for Quiplash 3: 5๐Ÿ‘ 1๐Ÿ‘Ž (Score: +4) ๐ŸŒ™ Game Night has ended! Thanks for playing! ๐Ÿ“Š Session Stats: 5 games played ``` ### Fallback Behavior The bot should also implement **polling detection** as a fallback in case the WebSocket connection fails or the event is not received: - Poll `GET /api/sessions/active` every 30 seconds - If a previously active session becomes inactive, treat it as a session end - This ensures the bot will always detect session endings, even without WebSocket ## ๐Ÿ” Debugging ### Check WebSocket Logs The backend logs WebSocket events: ``` [WebSocket] Client subscribed to session 17 [Sessions] Broadcasted session.ended event for session 17 [WebSocket] Broadcasted session.ended to 1 client(s) for session 17 ``` ### Common Issues 1. **Event not received:** - Verify the client is authenticated (`auth_success` received) - Verify the client is subscribed to the correct session - Check backend logs for broadcast confirmation 2. **Connection drops:** - Implement ping/pong heartbeat (send `{"type": "ping"}` every 30s) - Handle reconnection logic in your client 3. **Multiple events received:** - This is normal if multiple clients are subscribed - Each client receives its own copy of the event ## ๐Ÿ“š Related Documentation - [WebSocket Testing Guide](WEBSOCKET_TESTING.md) - [Bot Integration Guide](BOT_INTEGRATION.md) - [API Quick Reference](API_QUICK_REFERENCE.md) ## ๐Ÿ”— Related Events | Event Type | Description | When Triggered | |------------|-------------|----------------| | `session.started` | A new session was created | When session is created | | `game.added` | A new game was added to the session | When a game starts | | `session.ended` | The session has ended | When session is closed | | `vote.received` | A vote was cast for a game | When a user votes | ## ๐Ÿ“ Notes - The `session.ended` event is broadcast to **all clients subscribed to that session** - The event includes the final `games_played` count for the session - The `is_active` field will always be `0` for ended sessions - The timestamp is in ISO 8601 format with timezone (UTC)