import WebSocket, { WebSocketServer } from 'ws'; import https from 'https'; import fs from 'fs'; const PORT = Number.parseInt(process.env.DAEMON_PORT || '4551', 10); const USE_TLS = process.env.DAEMON_TLS === '1'; const TLS_KEY_PATH = process.env.DAEMON_TLS_KEY_PATH; const TLS_CERT_PATH = process.env.DAEMON_TLS_CERT_PATH; const TLS_CA_PATH = process.env.DAEMON_TLS_CA_PATH; // optional // Einfache In-Memory-Struktur für Verbindungen (für spätere Erweiterungen) const connections = new Set(); function createServer() { let wss; if (USE_TLS) { if (!TLS_KEY_PATH || !TLS_CERT_PATH) { console.error('[Daemon] DAEMON_TLS=1 gesetzt, aber DAEMON_TLS_KEY_PATH/DAEMON_TLS_CERT_PATH fehlen.'); process.exit(1); } const httpsServer = https.createServer({ key: fs.readFileSync(TLS_KEY_PATH), cert: fs.readFileSync(TLS_CERT_PATH), ca: TLS_CA_PATH ? fs.readFileSync(TLS_CA_PATH) : undefined, }); wss = new WebSocketServer({ server: httpsServer }); // Direkte Verbindung: lausche auf allen Interfaces (0.0.0.0) httpsServer.listen(PORT, '0.0.0.0', () => { console.log(`[Daemon] WSS (TLS) Server gestartet auf Port ${PORT}`); }); } else { // Direkte Verbindung: lausche auf allen Interfaces (0.0.0.0) wss = new WebSocketServer({ port: PORT, host: '0.0.0.0' }); console.log(`[Daemon] WS (ohne TLS) Server startet auf Port ${PORT} ...`); } wss.on('connection', (ws, req) => { const peer = req.socket.remoteAddress + ':' + req.socket.remotePort; ws.isAlive = true; ws.userId = null; connections.add(ws); console.log(`[Daemon] Neue Verbindung von ${peer}`); ws.on('message', (message) => { try { if (message.toString() === 'pong') { // Client-Pong für unser Ping ws.isAlive = true; return; } const data = JSON.parse(message.toString()); // Vom Frontend gesendet nach Verbindungsaufbau if (data.event === 'setUserId' && data.data?.userId) { ws.userId = data.data.userId; console.log(`[Daemon] setUserId erhalten: ${ws.userId}`); return; } // Admin-Dialog: WebSocket-Log anfordern if (data.event === 'getWebsocketLog') { const response = { event: 'getWebsocketLogResponse', entries: [] // aktuell keine Log-Historie implementiert }; ws.send(JSON.stringify(response)); return; } // Platzhalter für spätere Events // console.log('[Daemon] Unbekanntes Event:', data); } catch (err) { console.error('[Daemon] Fehler beim Verarbeiten einer Nachricht:', err); } }); ws.on('close', () => { connections.delete(ws); console.log('[Daemon] Verbindung geschlossen'); }); ws.on('error', (err) => { console.error('[Daemon] WebSocket-Fehler (Verbindung):', err); }); }); // Einfache Ping/Pong-Mechanik, damit Verbindungen sauber erkannt werden const interval = setInterval(() => { for (const ws of connections) { if (ws.isAlive === false) { console.log('[Daemon] Verbindung wegen fehlendem Pong beendet'); ws.terminate(); connections.delete(ws); continue; } ws.isAlive = false; try { ws.send('ping'); } catch (err) { console.error('[Daemon] Fehler beim Senden von Ping:', err); } } }, 30000); wss.on('close', () => { clearInterval(interval); connections.clear(); console.log('[Daemon] Server gestoppt'); }); wss.on('error', (err) => { console.error('[Daemon] Server-Fehler:', err); }); return wss; } createServer();