From d79c12b6e986cc5a52e9a8685a7cb67a7b37f062 Mon Sep 17 00:00:00 2001 From: Giuseppe Raffa <77052701+sesee3@users.noreply.github.com> Date: Tue, 14 Apr 2026 17:05:24 +0200 Subject: [PATCH] feat: implement sensor connection and health check endpoints --- realtime/src/index.js | 24 +++++++++++++- realtime/src/routes/connect.js | 35 +++++++++++++++++++++ realtime/src/routes/sensors.js | 14 +++++++++ realtime/src/store/db.js | 57 ++++++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 realtime/src/routes/connect.js create mode 100644 realtime/src/routes/sensors.js create mode 100644 realtime/src/store/db.js diff --git a/realtime/src/index.js b/realtime/src/index.js index 64b9a9c..cef5cf7 100644 --- a/realtime/src/index.js +++ b/realtime/src/index.js @@ -1,9 +1,31 @@ const express = require('express'); +const crypto = require('crypto'); const app = express(); +const db = require('./store/db') + app.use(express.json()); -app.get('/', (req, res) => {}); +// DATABASE POSTGRESQL + +app.get('/', (req, res) => { + res.redirect('/health'); +}); + +app.get('/health', (req, res) => { + + const sensorsDB = db.checkConnection('sensors'); + const dataDB = db.checkConnection('data'); + + res.json({ + status: 'ok', + sensorsDB: sensorsDB, + dataDB: dataDB + }); +}); + +app.use('/connect', require('./routes/connect')); +app.use('/sensors', require('./routes/sensors')); app.listen(3000, '0.0.0.0', () => { console.log(`Realtime started`); diff --git a/realtime/src/routes/connect.js b/realtime/src/routes/connect.js new file mode 100644 index 0000000..e6332b0 --- /dev/null +++ b/realtime/src/routes/connect.js @@ -0,0 +1,35 @@ +const router = require('express').Router(); +const db = require('../store/db'); +const crypto = require('crypto'); + +router.post('/connect/new', async (req, res) => { + const { name, code } = req.body; + + if (!name || !code) { + return res.status(400).json({ error: 'name and code are required' }); + } + + if (code.length < 6) { + return res.status(400).json({ error: 'code must be at least 6 characters' }); + } + + const salt = crypto.randomBytes(16).toString('hex'); + const hash = crypto.scryptSync(code, salt, 64).toString('hex'); + const codeHash = `${salt}:${hash}`; + + try { + await db.query('sensors', + 'INSERT INTO sensors (name, code_hash) VALUES ($1, $2)', + [name, codeHash] + ); + res.status(201).json({ status: 'ok' }); + } catch (err) { + if (err.code === '23505') { + return res.status(409).json({ error: 'name already exists' }); + } + console.error('Error creating sensor', err); + res.status(500).json({ error: 'internal server error' }); + } +}); + +module.exports = router; diff --git a/realtime/src/routes/sensors.js b/realtime/src/routes/sensors.js new file mode 100644 index 0000000..0b88c49 --- /dev/null +++ b/realtime/src/routes/sensors.js @@ -0,0 +1,14 @@ +const router = require('express').Router(); +const db = require('../store/db'); + +router.get('/sensors', async (req, res) => { + try { + const result = await db.query('SELECT id, name FROM sensors', [], 'sensors'); + res.json(result.rows); + } catch (err) { + console.error('Error fetching sensors', err); + res.status(500).json({ error: 'internal server error' }); + } +}); + +module.exports = router; \ No newline at end of file diff --git a/realtime/src/store/db.js b/realtime/src/store/db.js new file mode 100644 index 0000000..cfc4c4e --- /dev/null +++ b/realtime/src/store/db.js @@ -0,0 +1,57 @@ +const { Pool } = require('pg'); +const { get } = require('../../../api/src/routes/params.sensor'); + +const pool = new Pool({ + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + host: process.env.DB_HOST, + port: process.env.DB_PORT, + max: 10, + idleTimeoutMillis: 30000, + connectionTimeoutMillis: 5000, +}) + +const dbs = { + data: { name: process.env.DATA_DB }, + sensors: { name: process.env.SENSOR_DB } +} + +function getPool(db) { + const dbConfig = dbs[db]; + if (!dbConfig) throw new Error(`Database ${db} not configured`); + return new Pool({ ...pool.options, database: dbConfig.name }); +} + +async function checkConnection(db) { + try { + await getPool(db).query('SELECT NOW()'); + return true; + } catch (err) { + console.error(`Error connecting to ${db} database`, err); + return false; + } +} + +async function query(db, text, params) { + const pool = getPool(db); + return pool.query(text, params); +} + +async function init() { + try { + await query('sensors', ` + CREATE TABLE IF NOT EXISTS sensors ( + id SERIAL PRIMARY KEY, + name VARCHAR(255) UNIQUE NOT NULL, + code_hash TEXT NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW() + ); + `); + } catch (err) { + console.error('Error creating sensors table', err); + } +} + +init(); + +module.exports = { checkConnection, query }; \ No newline at end of file