116 lines
3.5 KiB
JavaScript
116 lines
3.5 KiB
JavaScript
const router = require('express').Router();
|
|
const crypto = require('crypto');
|
|
const { query } = require('../storage/postgres');
|
|
|
|
const sets = ['forecasts', 'sensors', 'marine'];
|
|
|
|
function hashSensorCode(code) {
|
|
return crypto.createHash('sha256').update(code).digest('hex');
|
|
}
|
|
|
|
/**
|
|
* Middleware: valida sensor code e verifica che il sensore sia attivo.
|
|
* Salva sensor.id in req.sensorId.
|
|
*/
|
|
async function authenticateSensor(req, res, next) {
|
|
const { sensorCode } = req.params;
|
|
try {
|
|
const hashed = hashSensorCode(sensorCode);
|
|
const sensor = await query(
|
|
'SELECT id, active FROM sensors WHERE code_hash = $1',
|
|
[hashed],
|
|
'sensors'
|
|
);
|
|
|
|
if (!sensor.rows[0]) {
|
|
return res.status(401).json({ error: 'Sensor code not valid' });
|
|
}
|
|
if (!sensor.rows[0].active) {
|
|
return res.status(403).json({ error: 'Sensor is not active' });
|
|
}
|
|
|
|
req.sensorId = sensor.rows[0].id;
|
|
next();
|
|
} catch (err) {
|
|
console.error('[PARAMS/SENSOR] Auth error:', err.message);
|
|
res.status(500).json({ error: 'Internal server error' });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET /params/sensor/:sensorCode/active?set=sensors
|
|
* Ritorna il set di parametri attivo (forecasts, sensors, marine)
|
|
*/
|
|
router.get('/:sensorCode/active', authenticateSensor, async (req, res) => {
|
|
const { set } = req.query;
|
|
|
|
if (!set || !sets.includes(set))
|
|
return res.status(400).json({ error: 'SET parameter invalid' });
|
|
|
|
try {
|
|
const result = await query(
|
|
`SELECT * FROM ${set} WHERE active = true LIMIT 1`,
|
|
[],
|
|
'references'
|
|
);
|
|
|
|
res.json(result.rows[0] || null);
|
|
} catch (err) {
|
|
console.error('[PARAMS/SENSOR] Error:', err.message);
|
|
res.status(500).json({ error: 'Internal server error' });
|
|
}
|
|
});
|
|
|
|
// --- Mapping tipo rules → tabelle ---
|
|
const RULES_TYPE_MAP = {
|
|
weather: { rules: 'weather', items: 'weatheritems' },
|
|
laterforecasts: { rules: 'laterforecasts', items: 'laterforecastitems' },
|
|
data: { rules: 'dataread', items: 'datareaditems' },
|
|
logs: { rules: 'logs', items: 'logitems' }
|
|
};
|
|
|
|
/**
|
|
* GET /params/sensor/:sensorCode/rules?type=weather
|
|
* Ritorna la rule attiva con items per il tipo specificato.
|
|
* Autenticazione tramite sensor code (non richiede JWT/API key).
|
|
*/
|
|
router.get('/:sensorCode/rules', authenticateSensor, async (req, res) => {
|
|
const { type } = req.query;
|
|
|
|
if (!type || !RULES_TYPE_MAP[type]) {
|
|
return res.status(400).json({ error: `invalid type, must be one of: ${Object.keys(RULES_TYPE_MAP).join(', ')}` });
|
|
}
|
|
|
|
const tables = RULES_TYPE_MAP[type];
|
|
|
|
try {
|
|
const { rows: ruleRows } = await query(
|
|
`SELECT * FROM ${tables.rules} WHERE active = true AND archived = false LIMIT 1`,
|
|
[], 'rules'
|
|
);
|
|
|
|
if (ruleRows.length === 0) {
|
|
return res.status(404).json({ error: `no active ${type} rule found` });
|
|
}
|
|
|
|
const rule = ruleRows[0];
|
|
const { rows: items } = await query(
|
|
`SELECT * FROM ${tables.items} WHERE rule_id = $1 AND enabled = true`,
|
|
[rule.id], 'rules'
|
|
);
|
|
|
|
res.json({
|
|
id: rule.id,
|
|
version: rule.version,
|
|
description: rule.description,
|
|
tags: rule.tags,
|
|
items
|
|
});
|
|
} catch (err) {
|
|
console.error('[PARAMS/SENSOR] Rules error:', err.message);
|
|
res.status(500).json({ error: 'Internal server error' });
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|