Files
jackboxpartypack-gamepicker/backend/server.js

72 lines
2.2 KiB
JavaScript
Raw Normal View History

2025-10-30 04:27:43 -04:00
require('dotenv').config();
const express = require('express');
2025-11-02 16:06:31 -05:00
const http = require('http');
2025-10-30 04:27:43 -04:00
const cors = require('cors');
const { bootstrapGames, bootstrapTickers } = require('./bootstrap');
2025-11-02 16:06:31 -05:00
const { WebSocketManager, setWebSocketManager } = require('./utils/websocket-manager');
const { cleanupAllShards } = require('./utils/ecast-shard-client');
2025-10-30 04:27:43 -04:00
const app = express();
const PORT = process.env.PORT || 5000;
// Middleware
app.use(cors());
app.use(express.json());
// Health check
app.get('/health', (req, res) => {
res.json({ status: 'ok', message: 'Jackbox Game Picker API is running' });
});
// Routes
const authRoutes = require('./routes/auth');
const gamesRoutes = require('./routes/games');
const sessionsRoutes = require('./routes/sessions');
feat: poll countdown timer, game-selection sync, source tracking, and multi-admin fixes Work spanning May 7-10 across multiple sessions: Poll winner detection + source column (May 7): - Fix race condition in handleEndPolling where WS voting.ended cleared leadingGame before the setTimeout could capture the winner - Add pollActiveRef guard to prevent late poll.leading messages from re-activating an ended poll - Add 'source' column to session_games (dice/manual/poll) with backward- compatible fallback from manually_added flag - Show indigo "Poll" badge in game lists (Picker, Home, SessionDetail) - Include source in session export (JSON and text formats) Multi-admin poll state sync (May 9): - Enrich poll.start broadcast with pollStartedAt timestamp so all admin clients can start their timers from the correct time - Enrich voting.ended broadcast with winnerGameId/Label/Votes so all admins see the winner prompt, not just the one who clicked End Poll - Add poll.start WS handler in SessionInfo so Admin B sees polls started by Admin A without refreshing - Make handleStartPolling optimistic with rollback on failure WebSocket keepalive + auto-reconnect (May 9): - Add 30s ping interval to SessionInfo WS connection (matching server's 60s timeout) to prevent silent disconnects - Add auto-reconnect on close with 3s delay - Proper cleanup of ping interval, reconnect timeout, and onclose handler Sync selected game across admin clients (May 10): - New POST/DELETE /sessions/:id/game-selection endpoints with DB persistence (pending_game_id, pending_game_source columns) - Broadcast game.picked/game.dismissed WS events to session subscribers - handleDismissGame replaces inline setSelectedGame(null) calls - Restore pending game selection on page load for late-joining admins - Clear pending selection when game is formally added to session Poll ending countdown timer (May 10): - POST /:id/voting/end now accepts optional { delay } (0-300 seconds) - New POST /:id/voting/cancel-end to abort a scheduled end - New poll.ending and poll.ending.cancelled WS events - poll_ending_at column on sessions table for crash recovery - rescheduleEndingPolls() called on server startup to resume countdowns - End Poll button opens popover with End Now / 5s / 10s / 30s / custom - Red "Poll Ending" card with countdown display and Cancel button - Document new WS events in docs/api/websocket.md Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 20:33:00 -04:00
const { rescheduleEndingPolls } = require('./routes/sessions');
2025-10-30 04:27:43 -04:00
const statsRoutes = require('./routes/stats');
const pickerRoutes = require('./routes/picker');
2025-11-02 16:06:31 -05:00
const votesRoutes = require('./routes/votes');
const webhooksRoutes = require('./routes/webhooks');
2025-10-30 04:27:43 -04:00
app.use('/api/auth', authRoutes);
app.use('/api/games', gamesRoutes);
app.use('/api/sessions', sessionsRoutes);
app.use('/api/stats', statsRoutes);
app.use('/api', pickerRoutes);
2025-11-02 16:06:31 -05:00
app.use('/api/votes', votesRoutes);
app.use('/api/webhooks', webhooksRoutes);
2025-10-30 04:27:43 -04:00
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!', message: err.message });
});
2025-11-02 16:06:31 -05:00
// Create HTTP server and attach WebSocket
const server = http.createServer(app);
// Initialize WebSocket Manager
const wsManager = new WebSocketManager(server);
setWebSocketManager(wsManager);
if (require.main === module) {
bootstrapGames();
bootstrapTickers();
server.listen(PORT, '0.0.0.0', () => {
console.log(`Server is running on port ${PORT}`);
console.log(`WebSocket server available at ws://localhost:${PORT}/api/sessions/live`);
feat: poll countdown timer, game-selection sync, source tracking, and multi-admin fixes Work spanning May 7-10 across multiple sessions: Poll winner detection + source column (May 7): - Fix race condition in handleEndPolling where WS voting.ended cleared leadingGame before the setTimeout could capture the winner - Add pollActiveRef guard to prevent late poll.leading messages from re-activating an ended poll - Add 'source' column to session_games (dice/manual/poll) with backward- compatible fallback from manually_added flag - Show indigo "Poll" badge in game lists (Picker, Home, SessionDetail) - Include source in session export (JSON and text formats) Multi-admin poll state sync (May 9): - Enrich poll.start broadcast with pollStartedAt timestamp so all admin clients can start their timers from the correct time - Enrich voting.ended broadcast with winnerGameId/Label/Votes so all admins see the winner prompt, not just the one who clicked End Poll - Add poll.start WS handler in SessionInfo so Admin B sees polls started by Admin A without refreshing - Make handleStartPolling optimistic with rollback on failure WebSocket keepalive + auto-reconnect (May 9): - Add 30s ping interval to SessionInfo WS connection (matching server's 60s timeout) to prevent silent disconnects - Add auto-reconnect on close with 3s delay - Proper cleanup of ping interval, reconnect timeout, and onclose handler Sync selected game across admin clients (May 10): - New POST/DELETE /sessions/:id/game-selection endpoints with DB persistence (pending_game_id, pending_game_source columns) - Broadcast game.picked/game.dismissed WS events to session subscribers - handleDismissGame replaces inline setSelectedGame(null) calls - Restore pending game selection on page load for late-joining admins - Clear pending selection when game is formally added to session Poll ending countdown timer (May 10): - POST /:id/voting/end now accepts optional { delay } (0-300 seconds) - New POST /:id/voting/cancel-end to abort a scheduled end - New poll.ending and poll.ending.cancelled WS events - poll_ending_at column on sessions table for crash recovery - rescheduleEndingPolls() called on server startup to resume countdowns - End Poll button opens popover with End Now / 5s / 10s / 30s / custom - Red "Poll Ending" card with countdown display and Cancel button - Document new WS events in docs/api/websocket.md Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 20:33:00 -04:00
rescheduleEndingPolls();
});
const shutdown = async () => {
console.log('Shutting down gracefully...');
await cleanupAllShards();
server.close(() => process.exit(0));
};
process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);
}
2025-10-30 04:27:43 -04:00
module.exports = { app, server };