Add new daemon start script and update localization for director salary

- Introduced a new script `start-daemon` in `package.json` for running the daemon server.
- Added translations for "director payed out" in both English and German localization files to enhance user notifications.
This commit is contained in:
Torsten Schulz (local)
2025-12-01 10:06:06 +01:00
parent d19feb8bc1
commit 17d4d21620
5 changed files with 109 additions and 5 deletions

98
backend/daemonServer.js Normal file
View File

@@ -0,0 +1,98 @@
import WebSocket, { WebSocketServer } from 'ws';
const PORT = 4551;
// Einfache In-Memory-Struktur für Verbindungen (für spätere Erweiterungen)
const connections = new Set();
function createServer() {
const wss = new WebSocketServer({ port: PORT });
console.log(`[Daemon] WebSocket-Server startet auf Port ${PORT} ...`);
wss.on('connection', (ws, req) => {
const peer = req.socket.remoteAddress + ':' + req.socket.remotePort;
ws.isAlive = true;
ws.userId = null;
connections.add(ws);
console.log(`[Daemon] Neue Verbindung von ${peer}`);
ws.on('message', (message) => {
try {
if (message.toString() === 'pong') {
// Client-Pong für unser Ping
ws.isAlive = true;
return;
}
const data = JSON.parse(message.toString());
// Vom Frontend gesendet nach Verbindungsaufbau
if (data.event === 'setUserId' && data.data?.userId) {
ws.userId = data.data.userId;
console.log(`[Daemon] setUserId erhalten: ${ws.userId}`);
return;
}
// Admin-Dialog: WebSocket-Log anfordern
if (data.event === 'getWebsocketLog') {
const response = {
event: 'getWebsocketLogResponse',
entries: [] // aktuell keine Log-Historie implementiert
};
ws.send(JSON.stringify(response));
return;
}
// Platzhalter für spätere Events
// console.log('[Daemon] Unbekanntes Event:', data);
} catch (err) {
console.error('[Daemon] Fehler beim Verarbeiten einer Nachricht:', err);
}
});
ws.on('close', () => {
connections.delete(ws);
console.log('[Daemon] Verbindung geschlossen');
});
ws.on('error', (err) => {
console.error('[Daemon] WebSocket-Fehler (Verbindung):', err);
});
});
// Einfache Ping/Pong-Mechanik, damit Verbindungen sauber erkannt werden
const interval = setInterval(() => {
for (const ws of connections) {
if (ws.isAlive === false) {
console.log('[Daemon] Verbindung wegen fehlendem Pong beendet');
ws.terminate();
connections.delete(ws);
continue;
}
ws.isAlive = false;
try {
ws.send('ping');
} catch (err) {
console.error('[Daemon] Fehler beim Senden von Ping:', err);
}
}
}, 30000);
wss.on('close', () => {
clearInterval(interval);
connections.clear();
console.log('[Daemon] Server gestoppt');
});
wss.on('error', (err) => {
console.error('[Daemon] Server-Fehler:', err);
});
return wss;
}
createServer();

View File

@@ -378,16 +378,19 @@ export async function createTriggers() {
tp.election_id, tp.election_id,
tp.tp_office_type_id, tp.tp_office_type_id,
tp.tp_election_date, tp.tp_election_date,
( COALESCE(
SELECT json_agg(vr) (
FROM votes vr SELECT json_agg(vr)
WHERE vr.election_id = tp.election_id FROM votes vr
WHERE vr.election_id = tp.election_id
),
'[]'::json -- oder '{}'::json, wenn dir ein Objekt lieber ist
), ),
NOW() AS created_at, NOW() AS created_at,
NOW() AS updated_at NOW() AS updated_at
FROM to_process tp FROM to_process tp
), ),
-- 10) Cleanup: Stimmen, Kandidaten und Wahlen löschen -- 10) Cleanup: Stimmen, Kandidaten und Wahlen löschen
_del_votes AS ( _del_votes AS (
DELETE FROM falukant_data.vote DELETE FROM falukant_data.vote

View File

@@ -7,6 +7,7 @@
"scripts": { "scripts": {
"start": "node server.js", "start": "node server.js",
"dev": "NODE_ENV=development node server.js", "dev": "NODE_ENV=development node server.js",
"start-daemon": "node daemonServer.js",
"sync-db": "node sync-database.js", "sync-db": "node sync-database.js",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },

View File

@@ -409,6 +409,7 @@
"Sell all products": "Alle Produkte verkauft", "Sell all products": "Alle Produkte verkauft",
"sell products": "Produkte verkauft", "sell products": "Produkte verkauft",
"director starts production": "Direktor beginnt Produktion", "director starts production": "Direktor beginnt Produktion",
"director payed out": "Direktorgehalt ausgezahlt",
"Buy storage (type: field)": "Lagerplatz gekauft (Typ: Feld)", "Buy storage (type: field)": "Lagerplatz gekauft (Typ: Feld)",
"Buy storage (type: iron)": "Lagerplatz gekauft (Typ: Eisen)", "Buy storage (type: iron)": "Lagerplatz gekauft (Typ: Eisen)",
"Buy storage (type: stone)": "Lagerplatz gekauft (Typ: Stein)", "Buy storage (type: stone)": "Lagerplatz gekauft (Typ: Stein)",

View File

@@ -42,6 +42,7 @@
"Sell all products": "Sell all products", "Sell all products": "Sell all products",
"sell products": "Sell products", "sell products": "Sell products",
"director starts production": "Director starts production", "director starts production": "Director starts production",
"director payed out": "Director salary paid out",
"Buy storage (type: field)": "Bought storage (type: field)", "Buy storage (type: field)": "Bought storage (type: field)",
"Buy storage (type: iron)": "Bought storage (type: iron)", "Buy storage (type: iron)": "Bought storage (type: iron)",
"Buy storage (type: stone)": "Bought storage (type: stone)", "Buy storage (type: stone)": "Bought storage (type: stone)",