// services/daemonWebSocketBridge.js import WebSocket from 'ws'; import { getIo } from '../utils/socket.js'; class DaemonWebSocketBridge { constructor() { this.daemonSocket = null; this.reconnectInterval = 5000; this.maxReconnectAttempts = 10; this.reconnectAttempts = 0; this.isConnected = false; } connect() { if (this.daemonSocket && this.daemonSocket.readyState === WebSocket.OPEN) { console.log('πŸ”Œ Daemon WebSocket bereits verbunden'); return; } const daemonUrl = process.env.DAEMON_WS_URL || 'wss://www.your-part.de:4551'; console.log('πŸ”Œ Verbinde mit Daemon WebSocket:', daemonUrl); try { this.daemonSocket = new WebSocket(daemonUrl); this.daemonSocket.on('open', () => { console.log('βœ… Daemon WebSocket verbunden'); this.isConnected = true; this.reconnectAttempts = 0; // Registriere uns beim Daemon this.send({ event: 'register_backend', data: { type: 'backend_bridge' } }); }); this.daemonSocket.on('message', (data) => { try { const message = JSON.parse(data.toString()); this.handleDaemonMessage(message); } catch (error) { console.error('❌ Fehler beim Parsen der Daemon-Nachricht:', error); } }); this.daemonSocket.on('close', (code, reason) => { console.log('❌ Daemon WebSocket getrennt:', code, reason.toString()); this.isConnected = false; this.scheduleReconnect(); }); this.daemonSocket.on('error', (error) => { console.error('❌ Daemon WebSocket Fehler:', error.message); this.isConnected = false; }); } catch (error) { console.error('❌ Fehler beim Erstellen der Daemon WebSocket-Verbindung:', error); this.scheduleReconnect(); } } handleDaemonMessage(message) { console.log('πŸ“¨ Daemon-Nachricht empfangen:', message); // Leite spezifische Events an Socket.io weiter if (message.event) { const io = getIo(); switch (message.event) { case 'production_ready': case 'stock_change': case 'price_update': case 'director_death': case 'production_started': case 'selled_items': case 'falukantUpdateStatus': case 'falukantBranchUpdate': case 'knowledge_update': case 'familychanged': // Broadcast an alle verbundenen Clients io.emit(message.event, message.data || {}); console.log(`πŸ“€ Event ${message.event} an alle Clients weitergeleitet:`, message.data || {}); break; case 'workerStatus': // Spezielle Behandlung fΓΌr Worker-Status io.emit('daemon_worker_status', message.data || {}); console.log('πŸ“€ Worker-Status an alle Clients weitergeleitet'); break; default: console.log('⚠️ Unbekanntes Daemon-Event:', message.event); } } } send(data) { if (this.daemonSocket && this.daemonSocket.readyState === WebSocket.OPEN) { this.daemonSocket.send(JSON.stringify(data)); } else { console.warn('⚠️ Daemon WebSocket nicht verbunden - kann Nachricht nicht senden'); } } scheduleReconnect() { if (this.reconnectAttempts >= this.maxReconnectAttempts) { console.error('❌ Maximale Wiederverbindungsversuche erreicht'); return; } this.reconnectAttempts++; const delay = Math.min(this.reconnectInterval * this.reconnectAttempts, 30000); console.log(`πŸ”„ Wiederverbindung in ${delay}ms (Versuch ${this.reconnectAttempts}/${this.maxReconnectAttempts})`); setTimeout(() => { this.connect(); }, delay); } disconnect() { if (this.daemonSocket) { this.daemonSocket.close(); this.daemonSocket = null; this.isConnected = false; } } getStatus() { return { connected: this.isConnected, reconnectAttempts: this.reconnectAttempts, readyState: this.daemonSocket ? this.daemonSocket.readyState : 'CLOSED' }; } } // Singleton-Instanz const daemonBridge = new DaemonWebSocketBridge(); export default daemonBridge;