const router = require('express').Router(); const express = require('express'); const path = require('path'); const fs = require('fs'); const configManager = require('../../config/configManager.js'); const layoutStore = require('../../tools/kiosk/server-layout-store.js'); const kioskPath = path.join(__dirname, '../../tools/kiosk'); const htmlFile = path.join(kioskPath, 'kiosk.html'); // API: layout corrente router.get('/layout', (req, res) => { const l = layoutStore.get(); if (!l) return res.status(404).json({ error: 'no layout' }); res.json(l); }); // SSE stream per gli update del layout (live, niente polling) router.get('/stream', (req, res) => { res.set({ 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'X-Accel-Buffering': 'no', }); res.flushHeaders?.(); // invia subito il layout corrente const cur = layoutStore.get(); if (cur) res.write(`event: layout\ndata: ${JSON.stringify(cur)}\n\n`); const off = layoutStore.onUpdate((layout) => { try { res.write(`event: layout\ndata: ${JSON.stringify(layout)}\n\n`); } catch {} }); const ping = setInterval(() => { try { res.write(': ping\n\n'); } catch {} }, 25000); req.on('close', () => { clearInterval(ping); off(); }); }); router.use('/', express.static(kioskPath)); router.get('/', (req, res) => { const apiUrl = process.env.API_URL || 'https://api.mebboat.it'; const realtimeUrl = process.env.REALTIME_URL || 'https://realtime.mebboat.it'; const realtimeWsUrl = process.env.REALTIME_SOCKET_URL || 'wss://realtime.mebboat.it'; const mapboxKey = process.env.MAPBOX_API_KEY || ''; const sensorCode = configManager.getSensorCode(); const sensorName = configManager.getSensorName(); const esc = (s) => String(s || '').replace(/"/g, '"'); const metas = ` `; let html; try { html = fs.readFileSync(htmlFile, 'utf8'); } catch (e) { return res.status(500).send('kiosk.html not found'); } html = html.replace('', metas + ''); res.set('Content-Type', 'text/html').send(html); }); module.exports = router;