Changeset 8f2f97c in Klonkt for src/server.js
- Timestamp:
- 06/23/2026 02:24:46 PM (3 months ago)
- Branches:
- main
- Children:
- cb01666
- Parents:
- 24cdcc6
- File:
-
- 1 edited
-
src/server.js (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/server.js
r24cdcc6 r8f2f97c 19 19 import { SqliteSessionStore } from './services/SqliteSessionStore.js'; 20 20 import { ensurePrimarySite } from './services/ensurePrimarySite.js'; 21 import PrutterService from './services/PrutterService.js';22 import { WebSocketServer } from 'ws';23 24 21 import { resolveSite, loadAudioTracks, loadTheme } from './middleware/site.js'; 25 22 import { isViewer } from './middleware/auth.js'; … … 36 33 import adminSettingsRoutes from './routes/admin-settings.js'; 37 34 import adminSeoRoutes from './routes/admin-seo.js'; 38 import prutterRoutes from './routes/prutter.js';39 35 import audioRoutes from './routes/audio.js'; 40 36 import searchRoutes from './routes/search.js'; … … 206 202 })(); 207 203 208 // Singleton PrutterService — routes get it via req.app.locals.prutter.209 const prutter = new PrutterService(db);210 app.locals.prutter = prutter;211 212 204 // Cirkels-federatie: publieke, site-agnostische endpoints (/.klonkt/*). 213 205 // Vóór resolveSite/theme — ze hebben geen site-context nodig. … … 274 266 app.use('/admin/epk', adminEpkRoutes); 275 267 app.use('/admin', adminRoutes); 276 app.use('/prutter', prutterRoutes);277 268 app.use('/audio', audioRoutes); 278 269 app.use('/search', searchRoutes); … … 422 413 }); 423 414 424 // ==================== WebSocket: Prutter real-time ====================425 // Authenticate via the existing session cookie. We reuse sessionMiddleware426 // during the HTTP upgrade so req.session is populated; if no user, abort.427 const wss = new WebSocketServer({ noServer: true });428 429 server.on('upgrade', (req, socket, head) => {430 if (req.url !== '/ws/prutter') {431 socket.destroy();432 return;433 }434 // Run session middleware on the upgrade request.435 // (Express's middleware accepts (req, res, next); we pass a stub res.)436 const stubRes = { setHeader: () => {}, getHeader: () => undefined, on: () => {}, end: () => {} };437 sessionMiddleware(req, stubRes, () => {438 if (!req.session?.user) {439 socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');440 socket.destroy();441 return;442 }443 // Kijker-accounts zijn alleen-lezen: weiger de WS-upgrade. De HTTP-guard444 // dekt geen WS, dus dit is de plek om schrijven via een (toekomstige)445 // message-handler te voorkomen.446 if (isViewer(req.session.user)) {447 socket.write('HTTP/1.1 403 Forbidden\r\n\r\n');448 socket.destroy();449 return;450 }451 wss.handleUpgrade(req, socket, head, (ws) => {452 ws.userId = req.session.user.id;453 wss.emit('connection', ws, req);454 });455 });456 });457 458 wss.on('connection', (ws) => {459 prutter.addConnection(ws.userId, ws);460 ws.on('close', () => prutter.removeConnection(ws.userId, ws));461 ws.on('error', () => prutter.removeConnection(ws.userId, ws));462 // Optional: ping every 30s to keep connections alive through proxies463 ws.isAlive = true;464 ws.on('pong', () => { ws.isAlive = true; });465 });466 const wsPing = setInterval(() => {467 for (const ws of wss.clients) {468 if (ws.isAlive === false) { ws.terminate(); continue; }469 ws.isAlive = false;470 try { ws.ping(); } catch {}471 }472 }, 30000);473 if (wsPing.unref) wsPing.unref();474 475 415 server.listen(PORT, () => { 476 416 console.log(''); … … 483 423 console.log(` ✓ Auth: wachtwoord (beheer) + Google (luisteraars) / logout`); 484 424 console.log(` ✓ Posts: create / edit / view / archive`); 485 console.log(` ✓ Realtime: WebSocket server ready (Prutter)`);486 425 console.log(''); 487 426 console.log(` Mode: ${isDev ? 'development' : 'PRODUCTION'}`);
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)