const path = require("path"); const express = require("express"); const WebSocket = require("ws"); const PORT = process.env.PORT || 3000; const UPSTREAM_URL = "wss://api.serwer.magico.pl/gastro_serwer"; const WS_ORIGIN = process.env.WS_ORIGIN || "https://serwer.magico.pl"; const WS_COOKIE = process.env.WS_COOKIE || ""; const WS_ACCESS_TOKEN = process.env.WS_ACCESS_TOKEN || "d55323bbe5fe56e5a7b9ecf657979a6d5ac49d00"; const app = express(); app.use(express.static(path.join(__dirname, "public"))); const browserClients = new Set(); let upstream = null; let reconnectTimer = null; let lastBillsSnapshot = null; function getDefaultInitMessages() { const list = []; // Z obserwacji aplikacji źródłowej: najpierw token, potem ustawienie kierunku. if (WS_ACCESS_TOKEN) { list.push({ cmd: "token", access_token: WS_ACCESS_TOKEN }); } list.push({ cmd: "kierunek", kierunek: "all" }); // Dodatkowe żądania pobrania aktualnych rachunków. list.push( { Type: "bills", kierunek: "all", type: "current" }, { type: "current", kierunek: "all" }, { action: "current" } ); return list; } function getInitMessages() { const raw = process.env.INIT_MESSAGES; if (!raw) return getDefaultInitMessages(); try { const parsed = JSON.parse(raw); if (Array.isArray(parsed)) return parsed; } catch (err) { console.warn("[CONFIG] INIT_MESSAGES is invalid JSON, using defaults:", err.message); } return getDefaultInitMessages(); } function broadcast(payload) { const text = JSON.stringify(payload); for (const client of browserClients) { if (client.readyState === WebSocket.OPEN) { client.send(text); } } } function connectUpstream() { if (upstream && (upstream.readyState === WebSocket.OPEN || upstream.readyState === WebSocket.CONNECTING)) { return; } console.log("[UPSTREAM] Connecting:", UPSTREAM_URL); upstream = new WebSocket(UPSTREAM_URL, { headers: { Origin: WS_ORIGIN, "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36", Pragma: "no-cache", "Cache-Control": "no-cache", ...(WS_COOKIE ? { Cookie: WS_COOKIE } : {}) } }); upstream.on("open", () => { console.log("[UPSTREAM] Connected"); broadcast({ event: "status", connected: true, ts: Date.now() }); // W wielu implementacjach połączenie zwraca dane dopiero po żądaniu inicjalnym. for (const msg of getInitMessages()) { try { upstream.send(JSON.stringify(msg)); console.log("[UPSTREAM] Sent init message:", msg); broadcast({ event: "sent", payload: msg, ts: Date.now() }); } catch (err) { console.warn("[UPSTREAM] Failed to send init message:", err.message); } } }); upstream.on("message", (data) => { const raw = data.toString(); let parsed = null; try { parsed = JSON.parse(raw); } catch { // wiadomość może być nie-JSON } if (parsed && parsed.Type === "bills" && Array.isArray(parsed.Bills)) { lastBillsSnapshot = { event: "snapshot", ts: Date.now(), parsed }; } broadcast({ event: "message", ts: Date.now(), raw, parsed }); }); upstream.on("close", (code, reasonBuffer) => { const reason = reasonBuffer ? reasonBuffer.toString() : ""; console.log(`[UPSTREAM] Closed (${code}) ${reason}`); broadcast({ event: "status", connected: false, code, reason, ts: Date.now() }); clearTimeout(reconnectTimer); reconnectTimer = setTimeout(connectUpstream, 3000); }); upstream.on("error", (err) => { console.error("[UPSTREAM] Error:", err.message); broadcast({ event: "error", message: err.message, ts: Date.now() }); }); } const server = app.listen(PORT, () => { console.log(`Viewer running at http://localhost:${PORT}`); connectUpstream(); }); const wss = new WebSocket.Server({ server, path: "/ws" }); wss.on("connection", (socket) => { browserClients.add(socket); socket.send(JSON.stringify({ event: "status", connected: upstream?.readyState === WebSocket.OPEN, ts: Date.now() })); if (lastBillsSnapshot) { socket.send(JSON.stringify(lastBillsSnapshot)); } socket.on("message", (raw) => { let data; try { data = JSON.parse(raw.toString()); } catch { return; } if (data.action === "sendUpstream" && data.payload && upstream?.readyState === WebSocket.OPEN) { try { const text = JSON.stringify(data.payload); upstream.send(text); console.log("[BROWSER->UPSTREAM]", text); broadcast({ event: "sent", payload: data.payload, ts: Date.now() }); } catch (err) { socket.send(JSON.stringify({ event: "error", message: err.message, ts: Date.now() })); } } }); socket.on("close", () => { browserClients.delete(socket); }); });