refactor: update WebSocket server setup and improve session handling
This commit is contained in:
@@ -182,6 +182,6 @@ services:
|
|||||||
|
|
||||||
networks:
|
networks:
|
||||||
meb-public:
|
meb-public:
|
||||||
external: true
|
internal: true
|
||||||
meb-private:
|
meb-private:
|
||||||
external: true
|
internal: true
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ app.use((req, res, next) => {
|
|||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
require('./socket');
|
|
||||||
|
|
||||||
app.get('/', (req, res) => {
|
app.get('/', (req, res) => {
|
||||||
res.redirect('/health');
|
res.redirect('/health');
|
||||||
});
|
});
|
||||||
@@ -81,6 +79,8 @@ const server = app.listen(3000, '0.0.0.0', async () => {
|
|||||||
await require('./helper/authdb').initDB();
|
await require('./helper/authdb').initDB();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
require('./socket')(server);
|
||||||
|
|
||||||
const wss = new WebSocket.Server({ server, path: '/live' });
|
const wss = new WebSocket.Server({ server, path: '/live' });
|
||||||
|
|
||||||
wss.on('connection', (client) => {
|
wss.on('connection', (client) => {
|
||||||
|
|||||||
@@ -5,8 +5,12 @@ const tokenStore = require('./helper/tokenStore');
|
|||||||
const redisHelper = require('./helper/redis');
|
const redisHelper = require('./helper/redis');
|
||||||
const influxWriter = require('./helper/influxWriter');
|
const influxWriter = require('./helper/influxWriter');
|
||||||
|
|
||||||
const ws = new WebSocket.Server({
|
module.exports = function setupSensorWebSocket(server) {
|
||||||
port: 3000,
|
const wsPath = process.env.SENSOR_WS_PATH || '/sensor';
|
||||||
|
|
||||||
|
const ws = new WebSocket.Server({
|
||||||
|
server,
|
||||||
|
path: wsPath,
|
||||||
perMessageDeflate: false,
|
perMessageDeflate: false,
|
||||||
verifyClient: async (info, callback) => {
|
verifyClient: async (info, callback) => {
|
||||||
const { query } = url.parse(info.req.url, true);
|
const { query } = url.parse(info.req.url, true);
|
||||||
@@ -28,15 +32,14 @@ const ws = new WebSocket.Server({
|
|||||||
callback(false, 500, `internal server error: ${error}`);
|
callback(false, 500, `internal server error: ${error}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.on('connection', async (client, req) => {
|
ws.on('connection', async (client, req) => {
|
||||||
const session = req.sensorSession;
|
const session = req.sensorSession;
|
||||||
const sensorId = session.sensorId;
|
const sensorId = session.sensorId;
|
||||||
|
|
||||||
client.sensorId = sensorId;
|
client.sensorId = sensorId;
|
||||||
|
|
||||||
// Registra la sessione su Redis
|
|
||||||
try {
|
try {
|
||||||
await redisHelper.setSession(sensorId, {
|
await redisHelper.setSession(sensorId, {
|
||||||
...session.metadata,
|
...session.metadata,
|
||||||
@@ -46,50 +49,28 @@ ws.on('connection', async (client, req) => {
|
|||||||
console.error(`[WS] Redis setSession error for ${sensorId}:`, err);
|
console.error(`[WS] Redis setSession error for ${sensorId}:`, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gestione messaggi in arrivo dal sensore.
|
|
||||||
*
|
|
||||||
* Il sensore invia dati codificati in MessagePack (binario).
|
|
||||||
* Il formato atteso è un array compatto (per risparmiare spazio):
|
|
||||||
*
|
|
||||||
* [timestamp, measurement, { field1: value1, field2: value2, ... }]
|
|
||||||
*
|
|
||||||
* Esempio pratico (dati meteo da barca):
|
|
||||||
* [1710681000, "weather", { t: 22.5, h: 65, p: 1013.2, w: 12.3 }]
|
|
||||||
*
|
|
||||||
* Dove le chiavi abbreviate sono:
|
|
||||||
* t = temperature, h = humidity, p = pressure, w = windSpeed ...
|
|
||||||
*
|
|
||||||
* Il server decodifica il messaggio e prepara il punto per InfluxDB.
|
|
||||||
*/
|
|
||||||
client.on('message', async (raw) => {
|
client.on('message', async (raw) => {
|
||||||
try {
|
try {
|
||||||
const msg = decode(raw);
|
const msg = decode(raw);
|
||||||
|
|
||||||
// Rispondi con ACK minimale in msgpack: { a: 1 } = acknowledged
|
|
||||||
client.send(encode({ a: 1 }));
|
client.send(encode({ a: 1 }));
|
||||||
|
|
||||||
const [timestamp, measurement, fields] = msg;
|
const [timestamp, measurement, fields] = msg;
|
||||||
|
|
||||||
// Pubblica su Redis per i watchers live
|
|
||||||
redisHelper.publishSensorData(sensorId, { timestamp, measurement, fields });
|
redisHelper.publishSensorData(sensorId, { timestamp, measurement, fields });
|
||||||
|
|
||||||
// Controlla se ci sono watchers attivi
|
|
||||||
const watchers = await redisHelper.getWatcherCount(sensorId);
|
const watchers = await redisHelper.getWatcherCount(sensorId);
|
||||||
|
|
||||||
if (measurement === 'forecast_batch') {
|
if (measurement === 'forecast_batch') {
|
||||||
influxWriter.writeForecastBatch(sensorId, fields);
|
influxWriter.writeForecastBatch(sensorId, fields);
|
||||||
} else if (watchers > 0) {
|
} else if (watchers > 0) {
|
||||||
// Con watchers: accumula nel buffer, flusha ogni 10 punti
|
|
||||||
influxWriter.bufferPoint(sensorId, timestamp, measurement, fields);
|
influxWriter.bufferPoint(sensorId, timestamp, measurement, fields);
|
||||||
} else {
|
} else {
|
||||||
// Senza watchers: scrivi immediatamente (comportamento originale)
|
|
||||||
influxWriter.writePoint(sensorId, timestamp, measurement, fields);
|
influxWriter.writePoint(sensorId, timestamp, measurement, fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`[WS|${sensorId}] decode error:`, err);
|
console.error(`[WS|${sensorId}] decode error:`, err);
|
||||||
// Rispondi con errore in msgpack: { e: 1 } = error
|
|
||||||
client.send(encode({ e: 1 }));
|
client.send(encode({ e: 1 }));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -105,6 +86,9 @@ ws.on('connection', async (client, req) => {
|
|||||||
console.error(`[WS] Redis deleteSession error for ${sensorId}:`, err);
|
console.error(`[WS] Redis deleteSession error for ${sensorId}:`, err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`[WS] Realtime websocket server`);
|
console.log(`[WS] Sensor websocket server ready on ${wsPath}`);
|
||||||
|
|
||||||
|
return ws;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user