Files
signalk-plugin/plugin/config.js
2026-03-11 15:25:03 +01:00

138 lines
4.9 KiB
JavaScript

const dotenv = require("dotenv");
const path = require("path");
const fs = require("fs");
dotenv.config({ path: path.resolve(__dirname, "..", ".env"), quiet: true });
const SIGNALK_FILES = process.env.SIGNALK_FILES || path.resolve(__dirname);
function checkFolder(dirPath) {
try {
fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);
} catch (err) {
if (err.code === 'ENOENT') {
fs.mkdirSync(dirPath, {
recursive: true,
mode: 0o777
});
} else {
throw new Error(`Permission denied for ${dirPath}`);
}
}
return dirPath;
}
const paths = {
base: SIGNALK_FILES,
logs: checkFolder(path.join(SIGNALK_FILES, "logs")),
hourlyArchive: path.join(SIGNALK_FILES, "logs", "hourly_archive.json"),
logsReferences: path.join(SIGNALK_FILES, "logs", "logs_references.json"),
savedDatas: checkFolder(path.join(SIGNALK_FILES, "logs", "saved_datas")),
private: checkFolder(path.join(SIGNALK_FILES, "private")),
authorizedAdmins: path.join(SIGNALK_FILES, "private", "authorized_admins.txt"),
telegramUsers: path.join(SIGNALK_FILES, "private", "telegram_users.json"),
sensorsReferences: path.join(__dirname, "sensors", "sensors.references.json")
};
const config = {
telegramBotToken: process.env.TELEGRAM_BOT_TOKEN,
mapboxKey: process.env.MAPBOX_KEY,
cloudUrl: process.env.CLOUD_URL || "https://realtime.mebcloud.it",
cloudApiKey: process.env.CLOUD_API_KEY,
realtimeUrl: process.env.REALTIME_URL || 'http://realtime:3002',
paths
};
/**
* Carica la configurazione sensori dal server (con fallback locale).
* Se viene fornito un ticket, usa l'endpoint autenticato /sensors/data/references.
* Altrimenti usa l'endpoint pubblico /sensors/references (legacy).
*
* @param {string|null} ticket - Ticket di autenticazione (opzionale)
* @returns {Promise<Object|null>} { items, version, isActive } o null
*/
async function loadSensorReferencesFromServer(ticket = null) {
// Tentativo 1: Endpoint autenticato (con ticket)
if (ticket) {
const authUrl = config.realtimeUrl + '/sensors/data/references';
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
const res = await fetch(authUrl, {
signal: controller.signal,
headers: { 'Authorization': `Bearer ${ticket}` }
});
clearTimeout(timeout);
if (res.ok) {
const data = await res.json();
console.log(`[MEB] Sensor references caricati (autenticato, v: ${data.version})`);
return data;
}
console.warn(`[MEB] Endpoint autenticato HTTP ${res.status}, provo fallback pubblico`);
} catch (err) {
console.warn(`[MEB] Endpoint autenticato fallito: ${err.message}, provo fallback pubblico`);
}
}
// Tentativo 2: Endpoint pubblico (legacy)
const publicUrl = config.realtimeUrl + '/sensors/references';
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
const res = await fetch(publicUrl, { signal: controller.signal });
clearTimeout(timeout);
if (res.ok) {
const data = await res.json();
console.log(`[MEB] Sensor references caricati dal server (versione: ${data.version})`);
return data;
}
console.warn(`[MEB] Server sensor refs HTTP ${res.status}, uso fallback locale`);
} catch (err) {
console.warn(`[MEB] Impossibile caricare sensor refs dal server: ${err.message}`);
}
// Tentativo 3: File locale
try {
const raw = fs.readFileSync(paths.sensorsReferences, 'utf-8');
const data = JSON.parse(raw);
console.log(`[MEB] Sensor references caricati da file locale (versione: ${data.version})`);
return data;
} catch (err) {
console.error(`[MEB] Nessuna sorgente sensor refs disponibile: ${err.message}`);
return null;
}
}
/**
* Controlla se la versione dei sensor references sul server e' cambiata.
* Ritorna la nuova versione se diversa, null altrimenti.
*/
async function checkSensorReferencesVersion(currentVersion) {
const url = config.realtimeUrl + '/sensors/references/version';
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 3000);
const res = await fetch(url, { signal: controller.signal });
clearTimeout(timeout);
if (res.ok) {
const data = await res.json();
if (data.version && data.version !== currentVersion) {
return data.version;
}
}
} catch {
// Silenzioso: il polling della versione non e' critico
}
return null;
}
module.exports = { config, paths, loadSensorReferencesFromServer, checkSensorReferencesVersion };