feat: update session handling and add session history endpoint

This commit is contained in:
Giuseppe Raffa
2026-04-16 15:37:10 +02:00
parent 5912c00a82
commit 981f498eb7
5 changed files with 354 additions and 92 deletions

View File

@@ -2,6 +2,7 @@ const { WebSocketServer } = require('ws');
const { decode } = require('@msgpack/msgpack');
const { consumeConnectionToken, appendAsConnection, query, hset, del } = require('../store/redis');
const { writeGenericData, writeForecastBatch } = require('../store/influx');
const db = require('../store/db');
// In-memory registries
const sensorWatchers = new Map(); // sensorName → Set<WebSocket> (watchers)
@@ -37,7 +38,6 @@ function setup(server) {
wss.handleUpgrade(req, socket, head, (ws) => {
ws.sensorName = sensor;
ws.sessionId = generateSessionId();
ws.sessionLabel = ws.sessionId;
ws.connectedAt = new Date().toISOString();
handleSensorConnection(ws);
});
@@ -54,15 +54,28 @@ function setup(server) {
});
}
function handleSensorConnection(ws) {
const { sensorName, sessionId, sessionLabel, connectedAt } = ws;
async function handleSensorConnection(ws) {
const { sensorName, sessionId, connectedAt } = ws;
console.log(`Sensor connected: ${sensorName} (session: ${sessionId})`);
// Register in global registry
connectedSensors.set(sensorName, ws);
appendAsConnection(sensorName, 'connected', connectedAt);
hset(`sensors:${sensorName}`, 'session', sessionId, 'sessionLabel', sessionLabel);
hset(`sensors:${sensorName}`, 'session', sessionId, 'connectedAt', connectedAt);
// Crea riga in sessiondataref su PostgreSQL (nome di default = sessionId)
try {
await db.query('sensors',
`INSERT INTO sessiondataref (session_id, sensor_name, name, created_at)
VALUES ($1, $2, $3, NOW())
ON CONFLICT (session_id) DO NOTHING`,
[sessionId, sensorName, sessionId]
);
console.log(`[${sensorName}] Session ${sessionId} registrata in sessiondataref`);
} catch (err) {
console.error(`[${sensorName}] Errore creazione sessiondataref:`, err.message);
}
const pingInterval = setInterval(() => {
if (ws.readyState === ws.OPEN) ws.ping();
@@ -84,19 +97,17 @@ function handleSensorConnection(ws) {
const { ts, _m, ...fields } = packet;
// Route per tipo di measurement
// InfluxDB: usa SEMPRE sessionId come tag (non cambia mai)
if (_m === 'forecast_batch') {
// Batch previsioni orarie
if (Array.isArray(fields.points)) {
writeForecastBatch(fields.points, sensorName, ws.sessionLabel);
writeForecastBatch(fields.points, sensorName, sessionId);
}
} else {
// weather, logs, o altro — scrivi tutti i campi
const measurement = _m || 'sensor_data';
writeGenericData(measurement, fields, sensorName, ws.sessionLabel, ts);
writeGenericData(measurement, fields, sensorName, sessionId, ts);
}
// Broadcast ai watchers: invia dati grezzi con measurement e fields
// Broadcast ai watchers
const watchers = sensorWatchers.get(sensorName);
if (watchers && watchers.size > 0) {
const msg = JSON.stringify({
@@ -115,11 +126,22 @@ function handleSensorConnection(ws) {
}
});
ws.on('close', () => {
ws.on('close', async () => {
console.log(`Sensor disconnected: ${sensorName}`);
clearInterval(pingInterval);
connectedSensors.delete(sensorName);
appendAsConnection(sensorName, 'disconnected', new Date().toISOString());
// Aggiorna disconnected_at in sessiondataref
try {
await db.query('sensors',
`UPDATE sessiondataref SET disconnected_at = NOW() WHERE session_id = $1`,
[sessionId]
);
} catch (err) {
console.error(`[${sensorName}] Errore update disconnected_at:`, err.message);
}
del(`sensors:${sensorName}`);
});