const WebSocket = require('ws'); const os = require('os'); const { encode } = require('@msgpack/msgpack'); const SOCKET_URL = process.env.REALTIME_SOCKET_URL; let ws = null; let onDisconnect = null; /** * Apre una connessione WebSocket al server realtime usando il token temporaneo. * @param {string} socketToken - Token temporaneo ottenuto da auth.authenticate() * @param {Function} onClose - Callback chiamata quando la connessione si chiude * @returns {Promise} true se la connessione è riuscita */ function connect(socketToken, onClose) { return new Promise((resolve) => { if (!SOCKET_URL) { console.error('[REALTIME|WS] REALTIME_SOCKET_URL non configurato nel .env'); return resolve(false); } onDisconnect = onClose; try { const wsUrl = `${SOCKET_URL}/?token=${encodeURIComponent(socketToken)}`; ws = new WebSocket(wsUrl); } catch (err) { console.error('[REALTIME|WS] Errore creazione:', err.message); return resolve(false); } ws.on('open', () => { console.log('[REALTIME|WS] Connesso'); // Invia init con system uptime const initPayload = { _t: 'init', uptime: Math.floor(os.uptime()) }; ws.send(encode(initPayload)); console.log('[REALTIME|WS] Init inviato:', initPayload); resolve(true); }); ws.on('message', () => { // Il server non invia messaggi ai sensori per ora }); ws.on('ping', () => { // ws risponde automaticamente con pong }); ws.on('error', (err) => { console.error(`[REALTIME|WS] Errore: ${err.message}`); resolve(false); }); ws.on('close', (code) => { console.log(`[REALTIME|WS] Disconnesso (code: ${code})`); ws = null; if (onDisconnect) onDisconnect(); }); }); } /** * Invia dati al server tramite WebSocket, codificati in msgpack. * @param {Array} data - Array nel formato [timestamp, measurement, fields] */ function send(data) { if (!ws || ws.readyState !== WebSocket.OPEN) return; try { const [timestamp, measurement, fields] = data; const packet = { ts: timestamp, _m: measurement, ...fields }; ws.send(encode(packet)); } catch (err) { console.error('[REALTIME|WS] Errore invio:', err.message); } } /** * Invia un oggetto raw al server, codificato in msgpack. * A differenza di send(), non fa transform [ts, measurement, fields]. * @param {Object} obj - Oggetto da inviare direttamente */ function sendRaw(obj) { if (!ws || ws.readyState !== WebSocket.OPEN) return; try { ws.send(encode(obj)); } catch (err) { console.error('[REALTIME|WS] Errore invio raw:', err.message); } } /** * @returns {boolean} true se la connessione è attiva */ function isConnected() { return ws !== null && ws.readyState === WebSocket.OPEN; } /** * Chiude la connessione WebSocket. */ function close() { onDisconnect = null; if (ws) { ws.close(); ws = null; } } module.exports = { connect, send, sendRaw, isConnected, close };