175 lines
4.8 KiB
JavaScript
175 lines
4.8 KiB
JavaScript
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);
|
|
});
|
|
});
|