UNPKG

camera.ui

Version:

NVR like user interface for RTSP capable cameras.

333 lines (273 loc) 8.59 kB
'use-strict'; import crypto from 'crypto'; import fs from 'fs-extra'; import path from 'path'; import { uiDefaults, defaultVideoProcess, permissionLevels, minNodeVersion, httpDefaults, ftpDefaults, mqttDefault, smtpDefaults, ConfigSetup, } from './config.defaults.js'; export default class ConfigService { static #secretPath; static name = 'camera.ui'; static configJson = {}; static restarted = false; //camera.ui env static storagePath; static configPath; static databasePath; static databaseUserPath; static databaseFilePath; static logPath; static logFile; static recordingsPath; static reportsPath; static debugEnabled; static version; //server env static minimumNodeVersion; static serviceMode; static env = {}; //defaults static ui = { port: uiDefaults.port, logLevel: '2', ssl: false, mqtt: false, topics: new Map(), http: false, smtp: false, options: { videoProcessor: defaultVideoProcess, }, cameras: [], version: '', }; static interface = { permissionLevels: permissionLevels, jwt_secret: null, }; constructor(configJson) { ConfigService.#secretPath = path.resolve(process.env.CUI_STORAGE_PATH, '.camera.ui.secrets'); //camera.ui env ConfigService.storagePath = process.env.CUI_STORAGE_PATH; ConfigService.configPath = process.env.CUI_STORAGE_CONFIG_FILE; ConfigService.databasePath = process.env.CUI_STORAGE_DATABASE_PATH; ConfigService.databaseUserPath = process.env.CUI_STORAGE_DATABASE_USER_PATH; ConfigService.databaseFilePath = process.env.CUI_STORAGE_DATABASE_FILE; ConfigService.logPath = process.env.CUI_STORAGE_LOG_PATH; ConfigService.logFile = process.env.CUI_STORAGE_LOG_FILE; ConfigService.recordingsPath = process.env.CUI_STORAGE_RECORDINGS_PATH; ConfigService.reportsPath = process.env.CUI_STORAGE_REPORTS_PATH; ConfigService.debugEnabled = process.env.CUI_LOG_MODE === '2'; ConfigService.version = process.env.CUI_VERSION; switch (process.env.CUI_LOG_MODE) { case '1': ConfigService.logLevel = 'info'; break; case '2': ConfigService.logLevel = 'debug'; break; case '3': ConfigService.logLevel = 'warn'; break; case '4': ConfigService.logLevel = 'error'; break; default: ConfigService.logLevel = 'info'; break; } //server env ConfigService.minimumNodeVersion = minNodeVersion; ConfigService.serviceMode = process.env.CUI_SERVICE_MODE === '2'; ConfigService.env = { moduleName: process.env.CUI_MODULE_NAME, global: process.env.CUI_MODULE_GLOBAL === '1', sudo: process.env.CUI_MODULE_SUDO === '1', }; //defaults ConfigService.ui.version = process.env.CUI_MODULE_VERSION; const config = new ConfigSetup(configJson); ConfigService.configJson = { ...config }; ConfigService.parseConfig(config); fs.ensureFileSync(ConfigService.configPath); fs.writeJSONSync(ConfigService.configPath, config, { spaces: 2 }); return { ui: ConfigService.ui, json: ConfigService.configJson, }; } static parseConfig(config = {}) { ConfigService.#config(config); ConfigService.#configInterface(); if (Array.isArray(config.cameras)) { ConfigService.#configCameras(config.cameras); } if (config.options) { ConfigService.#configOptions(config.options); } if (config.ssl) { ConfigService.#configSSL(config.ssl); } if (config.http) { ConfigService.#configHTTP(config.http); } if (config.smtp) { ConfigService.#configSMTP(config.smtp); } if (config.ftp) { ConfigService.#configFTP(config.ftp); } if (config.mqtt) { ConfigService.#configMQTT(config.mqtt); } } static writeToConfig(target, configJson) { let config = ConfigService.configJson; if (configJson) { if (config[target]) { config[target] = configJson; } else if (!target) { config = configJson; } else { throw new Error(`Can not save config, "${target}" not found in config!`, 'Config', 'system'); } } else { throw new Error('Can not save config, no config defined!', 'Config', 'system'); } config = new ConfigSetup(config); ConfigService.configJson = { ...config }; fs.writeJSONSync(ConfigService.configPath, config, { spaces: 2 }); ConfigService.parseConfig(config); } static #config(config = {}) { if (Number.parseInt(config.port)) { ConfigService.ui.port = config.port; } } static #configInterface() { const generateJWT = () => { const secrets = { jwt_secret: crypto.randomBytes(32).toString('hex'), }; ConfigService.interface.jwt_secret = secrets.jwt_secret; fs.ensureFileSync(ConfigService.#secretPath); fs.writeJsonSync(ConfigService.#secretPath, secrets, { spaces: 2 }); }; if (fs.pathExistsSync(ConfigService.#secretPath)) { try { const secrets = fs.readJsonSync(ConfigService.#secretPath); if (!secrets.jwt_secret) { generateJWT(); } else { ConfigService.interface.jwt_secret = secrets.jwt_secret; } } catch { generateJWT(); } } else { generateJWT(); } } static #configSSL(ssl = {}) { if (!ssl.active) { return; } if (ssl.key && ssl.cert) { ConfigService.ui.ssl = { key: fs.readFileSync(ssl.key, 'utf8'), cert: fs.readFileSync(ssl.cert, 'utf8'), }; } } static #configOptions(options = {}) { if (options.videoProcessor) { ConfigService.ui.options.videoProcessor = options.videoProcessor; } } static #configHTTP(http = {}) { if (!http.active) { return; } ConfigService.ui.http = { port: http.port || httpDefaults.port, localhttp: http.localhttp !== undefined ? http.localhttp : httpDefaults.localhttp, }; } static #configSMTP(smtp = {}) { if (!smtp.active) { return; } ConfigService.ui.smtp = { port: smtp.port || smtpDefaults.port, space_replace: smtp.space_replace || smtpDefaults.speace_replace, }; } static #configFTP(ftp = {}) { if (!ftp.active) { return; } ConfigService.ui.ftp = { port: ftp.port || ftpDefaults.port, useFile: ftp.useFile !== undefined ? ftp.useFile : ftpDefaults.useFile, }; } static #configMQTT(mqtt = {}) { if (!mqtt.active || !mqtt.host) { return; } ConfigService.ui.mqtt = { tls: mqtt.tls !== undefined ? mqtt.tls : mqttDefault.tls, host: mqtt.host, port: mqtt.port || mqttDefault.port, username: mqtt.username || mqttDefault.username, password: mqtt.password || mqttDefault.password, }; } static #configCameras(cameras = []) { ConfigService.ui.topics.clear(); ConfigService.ui.cameras = cameras.map((camera) => { if (camera.mqtt.motionTopic) { const mqttOptions = { motionTopic: camera.mqtt.motionTopic, motionMessage: camera.mqtt.motionMessage !== undefined ? camera.mqtt.motionMessage : 'ON', motionResetMessage: camera.mqtt.motionResetMessage !== undefined ? camera.mqtt.motionResetMessage : 'OFF', camera: camera.name, motion: true, }; ConfigService.ui.topics.set(mqttOptions.motionTopic, mqttOptions); } if (camera.mqtt.motionResetTopic && camera.mqtt.motionResetTopic !== camera.mqtt.motionTopic) { const mqttOptions = { motionResetTopic: camera.mqtt.motionResetTopic, motionResetMessage: camera.mqtt.motionResetMessage !== undefined ? camera.mqtt.motionResetMessage : 'OFF', camera: camera.name, motion: true, reset: true, }; ConfigService.ui.topics.set(mqttOptions.motionResetTopic, mqttOptions); } if ( camera.mqtt.doorbellTopic && camera.mqtt.doorbellTopic !== camera.mqtt.motionTopic && camera.mqtt.doorbellTopic !== camera.mqtt.motionResetTopic ) { const mqttOptions = { doorbellTopic: camera.mqtt.doorbellTopic, doorbellMessage: camera.mqtt.doorbellMessage !== undefined ? camera.mqtt.doorbellMessage : 'ON', camera: camera.name, doorbell: true, }; ConfigService.ui.topics.set(mqttOptions.doorbellTopic, mqttOptions); } return camera; }); } }