feat: add CORS support and enhance session routes for better sensor management
This commit is contained in:
78
realtime/client-example.js
Normal file
78
realtime/client-example.js
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
const WebSocket = require('ws');
|
||||||
|
const { encode } = require('@msgpack/msgpack');
|
||||||
|
|
||||||
|
const SERVER_URL = process.env.SERVER_URL || 'http://localhost:3000';
|
||||||
|
const WS_URL = process.env.WS_URL || 'ws://localhost:3000';
|
||||||
|
const SENSOR_NAME = process.env.SENSOR_NAME || 'sensor-01';
|
||||||
|
const SENSOR_CODE = process.env.SENSOR_CODE || 'password123';
|
||||||
|
|
||||||
|
async function authenticate() {
|
||||||
|
const res = await fetch(`${SERVER_URL}/connect/`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ name: SENSOR_NAME, code: SENSOR_CODE }),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
const err = await res.json();
|
||||||
|
throw new Error(`Auth failed: ${err.error}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
console.log('Authenticated, token received');
|
||||||
|
return data.t;
|
||||||
|
}
|
||||||
|
|
||||||
|
function connectWebSocket(token) {
|
||||||
|
const ws = new WebSocket(`${WS_URL}?token=${token}`);
|
||||||
|
|
||||||
|
ws.on('open', () => {
|
||||||
|
console.log('WebSocket connected');
|
||||||
|
startSendingData(ws);
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('pong', () => {
|
||||||
|
// Keepalive pong received
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('close', (code, reason) => {
|
||||||
|
console.log(`WebSocket closed: ${code} ${reason}`);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('error', (err) => {
|
||||||
|
console.error('WebSocket error:', err.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function startSendingData(ws) {
|
||||||
|
setInterval(() => {
|
||||||
|
if (ws.readyState !== WebSocket.OPEN) return;
|
||||||
|
|
||||||
|
const packet = {
|
||||||
|
ts: Date.now(),
|
||||||
|
t: 20 + Math.random() * 10, // temperature °C
|
||||||
|
h: 50 + Math.random() * 30, // humidity %
|
||||||
|
spd: Math.random() * 30, // speed
|
||||||
|
cog: Math.random() * 360, // course over ground
|
||||||
|
sog: 5 + Math.random() * 10, // speed over ground kn
|
||||||
|
hdg: Math.random() * 360, // heading true
|
||||||
|
lat: 43.7230 + Math.random() * 0.01, // latitude
|
||||||
|
lon: 10.3966 + Math.random() * 0.01, // longitude
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.send(Buffer.from(encode(packet)));
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
try {
|
||||||
|
const token = await authenticate();
|
||||||
|
connectWebSocket(token);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
@@ -8,6 +8,15 @@ const wsHandler = require('./ws/handler');
|
|||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
|
// CORS — consenti richieste dalla console e altri client browser
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
res.header('Access-Control-Allow-Origin', '*');
|
||||||
|
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||||
|
res.header('Access-Control-Allow-Headers', 'Content-Type');
|
||||||
|
if (req.method === 'OPTIONS') return res.sendStatus(204);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
// DATABASE POSTGRESQL
|
// DATABASE POSTGRESQL
|
||||||
|
|
||||||
app.get('/', (req, res) => {
|
app.get('/', (req, res) => {
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
const router = require('express').Router();
|
const router = require('express').Router();
|
||||||
const db = require('../store/db');
|
|
||||||
const { queryAll, query } = require('../store/redis');
|
const { queryAll, query } = require('../store/redis');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /sessions — Lista tutte le sessioni attive dei sensori.
|
||||||
|
* Legge da Redis le chiavi sensors:* (scritte da handler.js alla connessione)
|
||||||
|
*/
|
||||||
router.get('/', async (req, res) => {
|
router.get('/', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const keys = await queryAll('sensors');
|
const keys = await queryAll('sensors');
|
||||||
@@ -23,38 +26,57 @@ router.get('/', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/pending', (req, res) => {
|
/**
|
||||||
|
* GET /sessions/pending — Lista token di connessione pendenti.
|
||||||
|
* Legge da Redis le chiavi sensors_pending:* (create da createConnectionToken)
|
||||||
|
*/
|
||||||
|
router.get('/pending', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const pendingTokens = queryAll('snsr_pending_token');
|
const keys = await queryAll('sensors_pending');
|
||||||
res.json(pendingTokens);
|
res.json(keys);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error fetching pending tokens', err);
|
console.error('Error fetching pending tokens', err);
|
||||||
res.status(500).json({ error: `Error fetching pending tokens, ${err}` });
|
res.status(500).json({ error: `Error fetching pending tokens, ${err}` });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/connected', (req, res) => {
|
/**
|
||||||
|
* GET /sessions/connected — Lista sensori attualmente connessi.
|
||||||
|
* Legge da Redis le chiavi sensor:* (scritte da appendAsConnection in handler.js)
|
||||||
|
*/
|
||||||
|
router.get('/connected', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const connectedSensors = queryAll('snsr_connected');
|
const keys = await queryAll('sensor');
|
||||||
res.json(connectedSensors);
|
const connected = [];
|
||||||
|
for (const key of keys) {
|
||||||
|
const name = key.replace('sensor:', '');
|
||||||
|
const info = await query(name, 'sensor');
|
||||||
|
if (info.status === 'connected') {
|
||||||
|
connected.push({ name, connectedAt: info.timestamp });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.json(connected);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error fetching connected sensors', err);
|
console.error('Error fetching connected sensors', err);
|
||||||
res.status(500).json({ error: `Error fetching connected sensors, ${err}` });
|
res.status(500).json({ error: `Error fetching connected sensors, ${err}` });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /sessions/connected/:id — Verifica se un sensore specifico è connesso.
|
||||||
|
*/
|
||||||
router.get('/connected/:id', async (req, res) => {
|
router.get('/connected/:id', async (req, res) => {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
try {
|
try {
|
||||||
const sensor = await query(`snsr_connected:${id}`);
|
const info = await query(id, 'sensor');
|
||||||
if (!sensor) {
|
if (!info || info.status !== 'connected') {
|
||||||
return res.status(404).json({ error: 'sensor not connected' });
|
return res.status(404).json({ error: 'sensor not connected' });
|
||||||
}
|
}
|
||||||
res.json({ id, name: sensor });
|
res.json({ name: id, connectedAt: info.timestamp });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error fetching sensor connection status', err);
|
console.error('Error fetching sensor connection status', err);
|
||||||
res.status(500).json({ error: `Error fetching sensor connection status, ${err}` });
|
res.status(500).json({ error: `Error fetching sensor connection status, ${err}` });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ function handleSensorConnection(ws) {
|
|||||||
ws.on('message', (data) => {
|
ws.on('message', (data) => {
|
||||||
try {
|
try {
|
||||||
const packet = decode(data);
|
const packet = decode(data);
|
||||||
const { ts, ...fields } = packet;
|
const { ts, _m, ...fields } = packet;
|
||||||
|
|
||||||
writeSensorData(fields, sensorName, sessionId, ts);
|
writeSensorData(fields, sensorName, sessionId, ts);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user