/** * Relay HTTP → WS per il push dei rulesets ai sensori. * Chiamato SOLO dal servizio api (internal, x-api-key). * * POST /rules/push * Body: { sensors: [name, ...], type, ruleset } * -> invia msgpack { _t: 'ruleset_update', type, ruleset } ad ogni sensore * online tramite la connessione WS gia' stabilita. */ const router = require('express').Router(); const { encode } = require('@msgpack/msgpack'); const { connectedSensors } = require('../ws/handler'); const INTERNAL_KEY = process.env.INTERNAL_API_KEY; function requireInternal(req, res, next) { const k = req.headers['x-api-key']; if (!INTERNAL_KEY || !k || k !== INTERNAL_KEY) { return res.status(403).json({ error: 'forbidden' }); } next(); } router.post('/push', requireInternal, (req, res) => { const { sensors, type, ruleset } = req.body || {}; if (!Array.isArray(sensors) || !sensors.length) return res.status(400).json({ error: 'sensors array required' }); if (!type || !ruleset) return res.status(400).json({ error: 'type and ruleset required' }); const payload = { _t: 'ruleset_update', type, ruleset }; let encoded; try { encoded = encode(payload); } catch (err) { return res.status(500).json({ error: `encode error: ${err.message}` }); } const pushed = [], offline = [], errors = []; for (const name of sensors) { const ws = connectedSensors.get(name); if (!ws || ws.readyState !== ws.OPEN) { offline.push(name); continue; } try { ws.send(encoded); pushed.push(name); } catch (err) { errors.push({ sensor: name, error: err.message }); } } console.log(`[RULES] push type=${type} v=${ruleset?.version?.str || '?'} → pushed=${pushed.length} offline=${offline.length} err=${errors.length}`); res.json({ pushed, offline, errors }); }); module.exports = router;