diff --git a/backend/server.js b/backend/server.js index f06e2cc..031c3ec 100644 --- a/backend/server.js +++ b/backend/server.js @@ -4,7 +4,6 @@ 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); @@ -14,10 +13,6 @@ 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 deleted file mode 100644 index d87f674..0000000 --- a/backend/services/daemonWebSocketBridge.js +++ /dev/null @@ -1,233 +0,0 @@ -// 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'); - console.log('๐Ÿ” Daemon URL:', daemonUrl); - console.log('๐Ÿ” ReadyState:', this.daemonSocket.readyState); - console.log('๐Ÿ” Protocol:', this.daemonSocket.protocol); - console.log('๐Ÿ” Extensions:', this.daemonSocket.extensions); - this.isConnected = true; - this.reconnectAttempts = 0; - - // Registriere uns beim Daemon - console.log('๐Ÿ“ค Registriere Backend beim Daemon...'); - this.send({ - event: 'register_backend', - data: { type: 'backend_bridge' } - }); - }); - - this.daemonSocket.on('message', (data) => { - const rawMessage = data.toString(); - console.log('='.repeat(80)); - console.log('๐Ÿ“จ DAEMON โ†’ BACKEND'); - console.log('๐Ÿ“จ Raw Message:', rawMessage); - console.log('๐Ÿ“จ Lรคnge:', rawMessage.length); - console.log('๐Ÿ“จ Zeitstempel:', new Date().toISOString()); - - // Ignoriere ping/pong-Nachrichten - if (rawMessage === 'ping' || rawMessage === 'pong') { - console.log('๐Ÿ“ Ping/Pong-Nachricht ignoriert'); - console.log('='.repeat(80)); - return; - } - - try { - const message = JSON.parse(rawMessage); - console.log('โœ… JSON erfolgreich geparst'); - console.log('๐Ÿ“จ Parsed Message:', JSON.stringify(message, null, 2)); - this.handleDaemonMessage(message); - } catch (error) { - console.error('โŒ JSON Parse Fehler:'); - console.error('โŒ Error:', error.message); - console.error('โŒ Raw data:', rawMessage); - console.error('โŒ Hex:', Buffer.from(rawMessage, 'utf8').toString('hex')); - console.log('='.repeat(80)); - } - }); - - 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('๐Ÿ” BACKEND VERARBEITUNG'); - console.log('๐Ÿ” Message Type:', typeof message); - console.log('๐Ÿ” Message Keys:', Object.keys(message || {})); - - // Prรผfe verschiedene Nachrichtenformate - let eventName = null; - let eventData = {}; - - if (message.event) { - // Standard-Format: { event: 'eventName', data: {...} } - console.log('๐Ÿ” Format: Standard (event)'); - eventName = message.event; - eventData = message.data || {}; - } else if (message.type) { - // Alternative Format: { type: 'eventName', ... } - console.log('๐Ÿ” Format: Alternative (type)'); - eventName = message.type; - eventData = { ...message }; - delete eventData.type; - } else if (typeof message === 'string') { - // String-Format: 'eventName' - console.log('๐Ÿ” Format: String'); - eventName = message; - } else if (Array.isArray(message)) { - // Array-Format: ['eventName', {...}] - console.log('๐Ÿ” Format: Array'); - eventName = message[0]; - eventData = message[1] || {}; - } else { - console.log('โš ๏ธ Format: Unbekannt'); - eventName = 'unknown_event'; - eventData = message; - } - - console.log('๐Ÿ” Extracted Event:', eventName); - console.log('๐Ÿ” Extracted Data:', eventData); - - // Leite spezifische Events an Socket.io weiter - if (eventName) { - const io = getIo(); - console.log('๐Ÿ“ค BACKEND โ†’ FRONTEND'); - console.log('๐Ÿ“ค Socket.io verfรผgbar:', !!io); - console.log('๐Ÿ“ค Event Name:', eventName); - console.log('๐Ÿ“ค Event Data:', eventData); - - switch (eventName) { - 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 - console.log(`๐Ÿ“ค Sende Event "${eventName}" an alle Socket.io Clients...`); - if (io) { - io.emit(eventName, eventData); - console.log(`โœ… Event "${eventName}" erfolgreich an Socket.io gesendet`); - console.log(`โœ… Data:`, JSON.stringify(eventData, null, 2)); - } else { - console.error('โŒ Socket.io nicht verfรผgbar!'); - } - break; - - case 'workerStatus': - // Spezielle Behandlung fรผr Worker-Status - console.log(`๐Ÿ“ค Sende Worker-Status Event an alle Socket.io Clients...`); - if (io) { - io.emit('daemon_worker_status', eventData); - console.log(`โœ… Worker-Status erfolgreich an Socket.io gesendet`); - console.log(`โœ… Data:`, JSON.stringify(eventData, null, 2)); - } else { - console.error('โŒ Socket.io nicht verfรผgbar!'); - } - break; - - default: - console.log('โš ๏ธ Unbekanntes Daemon-Event:', eventName); - console.log('โš ๏ธ Event wird nicht weitergeleitet'); - } - } else { - console.log('โš ๏ธ Kein Event-Name extrahiert - keine Weiterleitung'); - } - - console.log('='.repeat(80)); - } - - send(data) { - console.log('๐Ÿ“ค BACKEND โ†’ DAEMON'); - console.log('๐Ÿ“ค Data:', JSON.stringify(data, null, 2)); - console.log('๐Ÿ“ค WebSocket Status:', this.daemonSocket ? this.daemonSocket.readyState : 'CLOSED'); - - if (this.daemonSocket && this.daemonSocket.readyState === WebSocket.OPEN) { - const message = JSON.stringify(data); - console.log('๐Ÿ“ค Sende an Daemon:', message); - this.daemonSocket.send(message); - console.log('โœ… Nachricht erfolgreich an Daemon gesendet'); - } else { - console.warn('โš ๏ธ Daemon WebSocket nicht verbunden - kann Nachricht nicht senden'); - console.warn('โš ๏ธ ReadyState:', this.daemonSocket ? this.daemonSocket.readyState : 'CLOSED'); - } - console.log('='.repeat(80)); - } - - 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/falukant/StatusBar.vue b/frontend/src/components/falukant/StatusBar.vue index 29ec93c..be7aad1 100644 --- a/frontend/src/components/falukant/StatusBar.vue +++ b/frontend/src/components/falukant/StatusBar.vue @@ -56,14 +56,25 @@ export default { }, async mounted() { await this.fetchStatus(); - this.setupSocketEvents(); + + // Live-Socket-Events + ["falukantUpdateStatus", "stock_change", "familychanged"].forEach(eventName => { + if (this.daemonSocket) { + this.daemonSocket.addEventListener('message', (event) => { + try { + const data = JSON.parse(event.data); + if (data.event === eventName) { + this.handleEvent(data); + } + } catch (error) { + // Ignore non-JSON messages like ping/pong + } + }); + } + }); }, beforeUnmount() { - if (this.socket) { - this.socket.off("falukantUpdateStatus"); - this.socket.off("stock_change"); - this.socket.off("familychanged"); - } + // Daemon WebSocket wird automatisch beim Logout geschlossen }, methods: { async fetchStatus() { @@ -106,27 +117,6 @@ export default { console.error("Error fetching status:", error); } }, - // Daemon WebSocket deaktiviert - verwende Socket.io Events - setupSocketEvents() { - if (this.socket) { - this.socket.on('falukantUpdateStatus', (data) => { - console.log('๐Ÿ“จ StatusBar: falukantUpdateStatus empfangen:', data); - this.handleEvent({ event: 'falukantUpdateStatus', ...data }); - }); - this.socket.on('stock_change', (data) => { - console.log('๐Ÿ“จ StatusBar: stock_change empfangen:', data); - this.handleEvent({ event: 'stock_change', ...data }); - }); - this.socket.on('familychanged', (data) => { - console.log('๐Ÿ“จ StatusBar: familychanged empfangen:', data); - this.handleEvent({ event: 'familychanged', ...data }); - }); - console.log('โœ… StatusBar: Socket.io Events registriert'); - } else { - console.log('โš ๏ธ StatusBar: Socket.io noch nicht verfรผgbar'); - setTimeout(() => this.setupSocketEvents(), 1000); - } - }, handleEvent(eventData) { console.log('๐Ÿ”„ StatusBar: handleEvent aufgerufen mit:', eventData); console.log('๐Ÿ”„ StatusBar: Event-Typ:', eventData.event); diff --git a/frontend/src/store/index.js b/frontend/src/store/index.js index 4532cbe..5aac9ff 100644 --- a/frontend/src/store/index.js +++ b/frontend/src/store/index.js @@ -122,102 +122,91 @@ 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 = () => { - if (currentDaemonSocket) { - currentDaemonSocket.disconnect(); - } - const daemonUrl = import.meta.env.VITE_DAEMON_SOCKET || 'wss://www.your-part.de:4551'; - console.log('๐Ÿ”Œ Initializing Daemon WebSocket connection to:', daemonUrl); - console.log('๐Ÿ”Œ Protocol:', 'yourpart-protocol'); - try { - // Versuche zuerst ohne Protokoll, da der Server es mรถglicherweise nicht unterstรผtzt - let daemonSocket; - try { - console.log('๐Ÿ”Œ Trying WebSocket connection without protocol...'); - daemonSocket = new WebSocket(daemonUrl); - } catch (error) { - console.error('โŒ Failed to create WebSocket:', error); - throw error; - } - - daemonSocket.onopen = () => { - console.log('โœ… Daemon WebSocket connected successfully'); - retryCount = 0; // Reset retry counter on successful connection - const payload = JSON.stringify({ - user_id: state.user.id, - event: 'setUserId', - data: { userId: state.user.id } - }); - daemonSocket.send(payload); - }; - - daemonSocket.onclose = (event) => { - console.warn('โŒ Daemon WebSocket disconnected:', event.reason); - console.warn('โŒ Close details:', { - code: event.code, - reason: event.reason, - wasClean: event.wasClean, - readyState: daemonSocket.readyState - }); - retryConnection(connectDaemonSocket); - }; - - daemonSocket.onerror = (error) => { - console.error('โŒ Daemon WebSocket error:', error); - console.error('โŒ Error details:', { - type: error.type, - target: error.target, - readyState: daemonSocket.readyState, - url: daemonSocket.url, - protocol: daemonSocket.protocol - }); - retryConnection(connectDaemonSocket); - }; - - daemonSocket.addEventListener('message', (event) => { - const message = event.data; - if (message === "ping") { - daemonSocket.send("pong"); - } else { - try { - const data = JSON.parse(message); - } catch (error) { - console.error("Error parsing message:", error); - } - } - }); - - commit('setDaemonSocket', daemonSocket); - } catch (error) { - console.error('โŒ Failed to create Daemon WebSocket:', error); - console.error('โŒ URL attempted:', import.meta.env.VITE_DAEMON_SOCKET); - retryConnection(connectDaemonSocket); - } - }; - - let retryCount = 0; - const maxRetries = 5; - const retryConnection = (reconnectFn) => { - if (retryCount >= maxRetries) { - console.error('โŒ Max retry attempts reached for Daemon WebSocket'); - return; - } - retryCount++; - const delay = Math.min(1000 * Math.pow(2, retryCount - 1), 10000); // Exponential backoff, max 10s - console.log(`๐Ÿ”„ Retrying Daemon WebSocket connection in ${delay}ms (attempt ${retryCount}/${maxRetries})`); - setTimeout(() => { - reconnectFn(); - }, delay); - }; - connectDaemonSocket(); + if (!state.isLoggedIn || !state.user) { + console.log("User is not logged in or user data is not available for Daemon WebSocket."); + return; } + + const daemonUrl = import.meta.env.VITE_DAEMON_SOCKET || 'wss://www.your-part.de:4551'; + console.log('๐Ÿ”Œ Initializing Daemon WebSocket connection to:', daemonUrl); + + const connectDaemonSocket = () => { + try { + const daemonSocket = new WebSocket(daemonUrl, 'yourpart-protocol'); + console.log('๐Ÿ”Œ Protocol: yourpart-protocol'); + + daemonSocket.onopen = () => { + console.log('โœ… Daemon WebSocket connected successfully'); + retryCount = 0; // Reset retry counter on successful connection + const payload = JSON.stringify({ + user_id: state.user.id, + event: 'setUserId', + data: { userId: state.user.id } + }); + daemonSocket.send(payload); + }; + + daemonSocket.onclose = (event) => { + console.warn('โŒ Daemon WebSocket disconnected:', event.reason); + console.warn('โŒ Close details:', { + code: event.code, + reason: event.reason, + wasClean: event.wasClean, + readyState: daemonSocket.readyState + }); + retryConnection(connectDaemonSocket); + }; + + daemonSocket.onerror = (error) => { + console.error('โŒ Daemon WebSocket error:', error); + console.error('โŒ Error details:', { + type: error.type, + target: error.target, + readyState: daemonSocket.readyState, + url: daemonSocket.url, + protocol: daemonSocket.protocol + }); + retryConnection(connectDaemonSocket); + }; + + daemonSocket.addEventListener('message', (event) => { + const message = event.data; + if (message === "ping") { + daemonSocket.send("pong"); + } else { + try { + const data = JSON.parse(message); + // Handle daemon messages here + console.log('๐Ÿ“จ Daemon message received:', data); + } catch (error) { + console.error("Error parsing daemon message:", error); + } + } + }); + + commit('setDaemonSocket', daemonSocket); + } catch (error) { + console.error('โŒ Failed to create Daemon WebSocket:', error); + console.error('โŒ URL attempted:', import.meta.env.VITE_DAEMON_SOCKET); + retryConnection(connectDaemonSocket); + } + }; + + let retryCount = 0; + const maxRetries = 5; + const retryConnection = (reconnectFn) => { + if (retryCount >= maxRetries) { + console.error('โŒ Max retry attempts reached for Daemon WebSocket'); + return; + } + retryCount++; + const delay = Math.min(1000 * Math.pow(2, retryCount - 1), 10000); // Exponential backoff, max 10s + console.log(`๐Ÿ”„ Retrying Daemon WebSocket connection in ${delay}ms (attempt ${retryCount}/${maxRetries})`); + setTimeout(() => { + reconnectFn(); + }, delay); + }; + connectDaemonSocket(); }, setLanguage({ commit }, language) { commit('setLanguage', language); diff --git a/frontend/src/views/falukant/BranchView.vue b/frontend/src/views/falukant/BranchView.vue index 7bad6fa..3d19102 100644 --- a/frontend/src/views/falukant/BranchView.vue +++ b/frontend/src/views/falukant/BranchView.vue @@ -55,7 +55,7 @@ export default { }, computed: { - ...mapState(['socket', 'daemonSocket']), + ...mapState(['daemonSocket']), }, async mounted() { @@ -72,58 +72,32 @@ export default { this.selectMainBranch(); } - // Daemon WebSocket deaktiviert - verwende Socket.io - this.setupSocketEvents(); - - // Live-Socket-Events - nur fรผr Events ohne spezielle Behandlung + // Live-Socket-Events [ - "production_ready", - "stock_change", - "price_update", - "director_death", - "production_started", - "selled_items", - "knowledge_update" + "production_ready", "stock_change", "price_update", + "director_death", "production_started", "selled_items", + "knowledge_update", "falukantUpdateStatus", "falukantBranchUpdate" ].forEach(eventName => { - if (this.socket) { - this.socket.on(eventName, data => this.handleEvent({ event: eventName, ...data })); + if (this.daemonSocket) { + this.daemonSocket.addEventListener('message', (event) => { + try { + const data = JSON.parse(event.data); + if (data.event === eventName) { + this.handleEvent(data); + } + } catch (error) { + // Ignore non-JSON messages like ping/pong + } + }); } }); }, beforeUnmount() { - if (this.socket) { - // Entferne spezielle Event-Listener - this.socket.off("falukantBranchUpdate"); - this.socket.off("falukantUpdateStatus"); - // Entferne allgemeine Event-Listener - this.socket.off("production_ready"); - this.socket.off("stock_change"); - this.socket.off("price_update"); - this.socket.off("director_death"); - this.socket.off("production_started"); - this.socket.off("selled_items"); - this.socket.off("knowledge_update"); - } + // Daemon WebSocket wird automatisch beim Logout geschlossen }, methods: { - setupSocketEvents() { - if (this.socket) { - this.socket.on('falukantBranchUpdate', (data) => { - console.log('๐Ÿ“จ BranchView: falukantBranchUpdate empfangen:', data); - this.handleEvent({ event: 'falukantBranchUpdate', ...data }); - }); - this.socket.on('falukantUpdateStatus', (data) => { - console.log('๐Ÿ“จ BranchView: falukantUpdateStatus empfangen:', data); - this.handleEvent({ event: 'falukantUpdateStatus', ...data }); - }); - console.log('โœ… BranchView: Socket.io Events registriert'); - } else { - console.log('โš ๏ธ BranchView: Socket.io noch nicht verfรผgbar'); - setTimeout(() => this.setupSocketEvents(), 1000); - } - }, async loadBranches() { try { const result = await apiClient.get('/api/falukant/branches');