whatsapp_bridge/server.js aktualisiert
Fix Error session end, fix error manual reconnect after crash.
This commit is contained in:
@@ -6,23 +6,73 @@ const path = require('path');
|
|||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
// Statische Dateien aus dem "ui" Ordner servieren
|
|
||||||
app.use(express.static(path.join(__dirname, 'ui')));
|
app.use(express.static(path.join(__dirname, 'ui')));
|
||||||
|
|
||||||
let lastQr = "";
|
let lastQr = "";
|
||||||
let isReady = false;
|
let isReady = false;
|
||||||
|
let isInitializing = true;
|
||||||
|
|
||||||
|
// Fester Speicherort für die Session außerhalb flüchtiger Docker-Verzeichnisse
|
||||||
const SESSION_DATA = '/data/auth';
|
const SESSION_DATA = '/data/auth';
|
||||||
|
|
||||||
|
// Sauberes Herunterfahren bei Abstürzen, um Dateikorruption der Session zu verhindern
|
||||||
|
async function handleCrash(errorContext) {
|
||||||
|
console.error(`💥 CRITICAL ERROR CAUGHT: ${errorContext}`);
|
||||||
|
isReady = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('Versuche Browser sauber zu schließen, um Session zu retten...');
|
||||||
|
if (client && client.pupBrowser) {
|
||||||
|
await client.pupBrowser.close().catch(() => {});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Browser konnte nicht sauber geschlossen werden:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Add-on wird beendet. HA Watchdog startet es sauber neu...');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sicherheitsnetz für ungefangene Puppeteer/Browser-Fehler
|
||||||
|
process.on('uncaughtException', async (err) => {
|
||||||
|
if (err.message.includes('ProtocolError') || err.message.includes('Runtime.callFunctionOn') || err.message.includes('Target closed')) {
|
||||||
|
await handleCrash('Puppeteer Protocol Timeout / Crash');
|
||||||
|
} else {
|
||||||
|
console.error('Uncaught Exception:', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('unhandledRejection', async (reason, promise) => {
|
||||||
|
if (reason && reason.message && reason.message.includes('Session closed')) {
|
||||||
|
await handleCrash('Unhandled Puppeteer Session Rejection');
|
||||||
|
} else {
|
||||||
|
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Client-Definition mit fixierter Client-ID gegen Session-Verlust
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
authStrategy: new LocalAuth({ dataPath: SESSION_DATA }),
|
authStrategy: new LocalAuth({
|
||||||
|
dataPath: SESSION_DATA,
|
||||||
|
clientId: "ha_bridge_session"
|
||||||
|
}),
|
||||||
|
authTimeoutMs: 90000,
|
||||||
|
qrMaxRetries: 5,
|
||||||
puppeteer: {
|
puppeteer: {
|
||||||
executablePath: '/usr/bin/chromium-browser',
|
executablePath: '/usr/bin/chromium-browser',
|
||||||
|
protocolTimeout: 0,
|
||||||
args: [
|
args: [
|
||||||
'--no-sandbox',
|
'--no-sandbox',
|
||||||
'--disable-setuid-sandbox',
|
'--disable-setuid-sandbox',
|
||||||
'--disable-dev-shm-usage',
|
'--disable-dev-shm-usage',
|
||||||
'--disable-gpu'
|
'--disable-gpu',
|
||||||
|
'--no-first-run',
|
||||||
|
'--no-zygote',
|
||||||
|
'--single-process',
|
||||||
|
'--disable-extensions',
|
||||||
|
'--disable-background-timer-throttling',
|
||||||
|
'--disable-backgrounding-occluded-windows',
|
||||||
|
'--disable-renderer-backgrounding'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -31,57 +81,71 @@ const client = new Client({
|
|||||||
client.on('qr', (qr) => {
|
client.on('qr', (qr) => {
|
||||||
lastQr = qr;
|
lastQr = qr;
|
||||||
isReady = false;
|
isReady = false;
|
||||||
|
isInitializing = false;
|
||||||
console.log('Neuer QR Code generiert.');
|
console.log('Neuer QR Code generiert.');
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('ready', () => {
|
client.on('ready', () => {
|
||||||
isReady = true;
|
isReady = true;
|
||||||
lastQr = "";
|
lastQr = "";
|
||||||
console.log('WhatsApp ist bereit!');
|
isInitializing = false;
|
||||||
|
console.log('WhatsApp ist bereit! Session wurde erfolgreich geladen/gespeichert.');
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on('disconnected', async (reason) => {
|
||||||
|
console.log(`WhatsApp Verbindung manuell oder extern getrennt (Grund: ${reason}).`);
|
||||||
|
await handleCrash('Externer Disconnect');
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- ROUTES ---
|
// --- ROUTES ---
|
||||||
|
|
||||||
// Hauptseite für Ingress
|
|
||||||
app.get('/', (req, res) => {
|
app.get('/', (req, res) => {
|
||||||
res.sendFile(path.join(__dirname, 'ui', 'index.html'));
|
res.sendFile(path.join(__dirname, 'ui', 'index.html'));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Status API
|
|
||||||
app.get('/api/status', async (req, res) => {
|
app.get('/api/status', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
let qrData = null;
|
let qrData = null;
|
||||||
if (lastQr) {
|
if (lastQr) {
|
||||||
qrData = await qrcode.toDataURL(lastQr);
|
qrData = await qrcode.toDataURL(lastQr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let clientState = 'DISCONNECTED';
|
||||||
|
if (isReady) {
|
||||||
|
clientState = await client.getState().catch(() => 'ERROR');
|
||||||
|
}
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
isReady: isReady,
|
isReady: isReady,
|
||||||
hasQr: lastQr !== "",
|
hasQr: lastQr !== "",
|
||||||
qrCode: qrData
|
qrCode: qrData,
|
||||||
|
isInitializing: isInitializing,
|
||||||
|
clientState: clientState
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
res.status(500).json({ error: e.message });
|
res.status(500).json({ error: e.message });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Logout
|
// Logout & Session-Löschung (Nur bei explizitem Klick auf "Account wechseln")
|
||||||
app.post('/auth/logout', async (req, res) => {
|
app.post('/auth/logout', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
await client.logout();
|
console.log("Manueller Logout über Web-UI...");
|
||||||
await fs.remove(SESSION_DATA);
|
await client.logout().catch(() => {});
|
||||||
res.json({ success: true, message: "Erfolgreich abgemeldet. Addon startet neu..." });
|
await fs.remove(path.join(SESSION_DATA, 'session-ha_bridge_session')).catch(() => {});
|
||||||
|
res.json({ success: true, message: "Erfolgreich abgemeldet. Ordner gelöscht. Addon startet neu..." });
|
||||||
setTimeout(() => process.exit(0), 2000);
|
setTimeout(() => process.exit(0), 2000);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.status(500).json({ error: err.message });
|
res.status(500).json({ error: err.message });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reset
|
// Factory Reset
|
||||||
app.delete('/system/reset', async (req, res) => {
|
app.delete('/system/reset', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
await client.destroy();
|
await client.destroy().catch(() => {});
|
||||||
await fs.emptyDir('/data');
|
await fs.emptyDir('/data').catch(() => {});
|
||||||
res.json({ success: true, message: "Werkseinstellungen wiederhergestellt. Addon startet neu..." });
|
res.json({ success: true, message: "Werkseinstellungen aktiv. Alles gelöscht. Neustart..." });
|
||||||
setTimeout(() => process.exit(0), 2000);
|
setTimeout(() => process.exit(0), 2000);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.status(500).json({ error: err.message });
|
res.status(500).json({ error: err.message });
|
||||||
@@ -101,5 +165,9 @@ app.post('/send', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
client.initialize();
|
console.log('Initialisiere WhatsApp Client...');
|
||||||
|
client.initialize().catch(async (err) => {
|
||||||
|
await handleCrash(`Initialisierungsfehler: ${err.message}`);
|
||||||
|
});
|
||||||
|
|
||||||
app.listen(3000, () => console.log('WhatsApp Bridge Server läuft auf Port 3000'));
|
app.listen(3000, () => console.log('WhatsApp Bridge Server läuft auf Port 3000'));
|
||||||
Reference in New Issue
Block a user