Änderungen: - Hinzufügen von detaillierten Protokollausgaben beim Verbindungsaufbau und beim Empfang von Nachrichten, um den Status und die empfangenen Daten besser nachzuvollziehen. - Implementierung von Protokollausgaben zur Unterscheidung zwischen verschiedenen Nachrichtenformaten und zur Dokumentation der Weiterleitung von Events an Socket.io. - Verbesserung der Fehlerbehandlung beim Parsen von JSON-Nachrichten mit zusätzlichen Protokollausgaben zur Diagnose. Diese Anpassungen erhöhen die Nachvollziehbarkeit der WebSocket-Interaktionen und erleichtern die Fehlersuche im Backend.
234 lines
9.2 KiB
JavaScript
234 lines
9.2 KiB
JavaScript
// 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;
|