diff --git a/backend/server.js b/backend/server.js index 031c3ec..f06e2cc 100644 --- a/backend/server.js +++ b/backend/server.js @@ -4,6 +4,7 @@ import http from 'http'; import app from './app.js'; import { setupWebSocket } from './utils/socket.js'; import { syncDatabase } from './utils/syncDatabase.js'; +import daemonBridge from './services/daemonWebSocketBridge.js'; const server = http.createServer(app); @@ -13,6 +14,10 @@ syncDatabase().then(() => { const port = process.env.PORT || 3001; server.listen(port, () => { console.log('Server is running on port', port); + + // Starte Daemon WebSocket Bridge + console.log('🔌 Starte Daemon WebSocket Bridge...'); + daemonBridge.connect(); }); }).catch(err => { console.error('Failed to sync database:', err); diff --git a/backend/services/daemonWebSocketBridge.js b/backend/services/daemonWebSocketBridge.js new file mode 100644 index 0000000..ba1bec0 --- /dev/null +++ b/backend/services/daemonWebSocketBridge.js @@ -0,0 +1,143 @@ +// 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`); + 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; diff --git a/frontend/src/components/AppFooter.vue b/frontend/src/components/AppFooter.vue index b76c342..895645d 100644 --- a/frontend/src/components/AppFooter.vue +++ b/frontend/src/components/AppFooter.vue @@ -51,14 +51,12 @@ export default { toggleDialogMinimize(dialogName) { this.$store.dispatch('dialogs/toggleDialogMinimize', dialogName); }, + // Daemon WebSocket deaktiviert - diese Funktionen sind nicht mehr verfügbar async showFalukantDaemonStatus() { - if (this.daemonSocket && this.daemonSocket.send) { - this.daemonSocket.send('{"event": "getWorkerStatus"}'); - } + console.log('⚠️ Daemon WebSocket deaktiviert - Status nicht verfügbar'); }, handleDaemonMessage(event) { - const status = JSON.parse(event.data); - console.log(event); + console.log('⚠️ Daemon WebSocket deaktiviert - keine Nachrichten verarbeitet'); } } }; diff --git a/frontend/src/components/falukant/StatusBar.vue b/frontend/src/components/falukant/StatusBar.vue index 19a0fd8..8522211 100644 --- a/frontend/src/components/falukant/StatusBar.vue +++ b/frontend/src/components/falukant/StatusBar.vue @@ -109,22 +109,8 @@ export default { console.error("Error fetching status:", error); } }, - async handleDaemonSocketMessage(event) { - try { - if (event.data === 'ping') { - return; - } - const data = JSON.parse(event.data); - if (data.event === "falukantUpdateStatus") { - this.fetchStatus(); - } - if (data.event === 'stock_change' || data.event === 'familychanged') { - this.fetchStatus(); - } - } catch (error) { - console.error("Error parsing daemonSocket message:", error, event.data); - } - }, + // Daemon WebSocket deaktiviert - verwende Socket.io Events + // Diese Methode wird nicht mehr verwendet openPage(url, hasSubmenu = false) { if (hasSubmenu) { return; diff --git a/frontend/src/store/index.js b/frontend/src/store/index.js index 2525b85..4532cbe 100644 --- a/frontend/src/store/index.js +++ b/frontend/src/store/index.js @@ -122,6 +122,11 @@ const store = createStore({ } }, initializeDaemonSocket({ commit, state }) { + // Daemon WebSocket temporär deaktiviert aufgrund von CORS/Protokoll-Problemen + // Socket.io wird für alle Events verwendet + console.log('🔌 Daemon WebSocket deaktiviert - verwende Socket.io für alle Events'); + return; + if (state.isLoggedIn && state.user) { let currentDaemonSocket = state.daemonSocket; const connectDaemonSocket = () => { diff --git a/frontend/src/views/falukant/BranchView.vue b/frontend/src/views/falukant/BranchView.vue index c8eca55..7bb05f9 100644 --- a/frontend/src/views/falukant/BranchView.vue +++ b/frontend/src/views/falukant/BranchView.vue @@ -72,10 +72,8 @@ export default { this.selectMainBranch(); } - // Daemon-Socket - if (this.daemonSocket) { - this.daemonSocket.addEventListener('message', this.handleDaemonMessage); - } + // Daemon WebSocket deaktiviert - verwende Socket.io + console.log('✅ BranchView: Socket.io Events werden verwendet'); // Live-Socket-Events [ diff --git a/frontend/src/views/falukant/OverviewView.vue b/frontend/src/views/falukant/OverviewView.vue index 9f9bd97..91a5676 100644 --- a/frontend/src/views/falukant/OverviewView.vue +++ b/frontend/src/views/falukant/OverviewView.vue @@ -207,24 +207,13 @@ export default { await this.fetchFalukantUser(); await this.fetchAllStock(); await this.fetchProductions(); + // Daemon WebSocket deaktiviert - verwende Socket.io für alle Events if (this.socket) { this.socket.on("falukantUserUpdated", this.fetchFalukantUser); this.socket.on("production_ready", this.handleProductionReadyEvent); - } - if (this.daemonSocket) { - this.daemonSocket.addEventListener('message', (event) => { - try { - if (event.data === "ping") return; - const message = JSON.parse(event.data); - if (message.event === 'production_ready') { - this.handleProductionReadyEvent(message); - } - } catch (error) { - console.error('Error processing WebSocket message in FalukantOverviewView:', error); - } - }); + console.log('✅ FalukantOverviewView: Socket.io Events registriert'); } else { - console.log('no daemon socket'); + console.log('⚠️ FalukantOverviewView: Kein Socket.io verfügbar'); } }, beforeUnmount() { @@ -232,9 +221,7 @@ export default { this.socket.off("falukantUserUpdated", this.fetchFalukantUser); this.socket.off("production_ready", this.handleProductionReadyEvent); } - if (this.daemonSocket) { - this.daemonSocket.onmessage = null; - } + // Daemon WebSocket deaktiviert - keine Cleanup nötig }, methods: { getAgeGroup(age) {