UNPKG

domotz-remote-pawn

Version:

Domotz Agent

356 lines (341 loc) 15.4 kB
/** * This file is part of Domotz Agent. * * @license * Domotz Agent is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Domotz Agent is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Domotz Agent. If not, see <http://www.gnu.org/licenses/>. * * @requires sandbox/library/device * @requires sandbox/library/crypto * @requires sandbox/library/buffer * @copyright Copyright (C) Domotz Inc */ /** * The Domotz Context Library * Used for accessing the domotz context within a custom driver. * Exposes the device namespace for any device related operations, utility libraries and driver callbacks * @namespace D */ /** * Custom Driver device credentials * @typedef {Object} DeviceCredentials * @readonly * @property {string} username - The device username * @property {string} password - The device password */ /** * The Cheerio Library Accepted Options * @typedef {Object} CheerioOptions * @see {@link https://cheerio.js.org/interfaces/CheerioOptions.html} */ /** * The Cheerio Library Loaded Document Interface. * Can be used to traverse and manipulate the loaded document. * @typedef {Object} CheerioAPI * @see {@link https://cheerio.js.org/interfaces/CheerioAPI.html} */ /** * Used when the result of a call towards a device is in an erroneous state * @typedef {Object} ErrorResult * @property {string} message - The Error Message */ const bufferLibrary = require('./library/buffer'); const cryptoLibrary = require('./library/crypto'); const deviceLibrary = require('./library/device'); const parameterLibrary = require('./library/parameter'); const tableLibrary = require('./library/table'); const variableLibrary = require('./library/variable'); const driverTypes = require('./constants').driverTypes; const errorTypes = require('./constants').errorTypes; const valueTypes = require('./constants').valueTypes; var driverVariable; var driverTable; var agentDriverSettings = null; var contextParameterLibrary = null; module.exports.createDomotzContext = function (message, newConsole) { agentDriverSettings = message.agentDriverSettings; contextParameterLibrary = parameterLibrary.parameterLibrary(newConsole, message.parameters); var DomotzContext = { /** * Creates an External IP device object * @example D.createExternalDevice("1.1.1.1", {"username": "root", "password": D.device.password()}) * @param {string} deviceHost - The IP or Hostname of the external device * @param {DeviceCredentials} [deviceCredentials] - The credentials for the external device * @memberof D * @readonly * @return {device} - The External Device object */ createExternalDevice: function (deviceHost, deviceCredentials) { var externalDevice = { ip: deviceHost, credentials: deviceCredentials, }; return deviceLibrary.device(externalDevice, agentDriverSettings, newConsole); }, /** * The Custom Driver Crypto object. * Contains utility functions that offer ways of encapsulating secure credentials to be used * as part of a secure HTTPS net or http connection. * Offers a set of wrappers for OpenSSL's hash, hmac, cipher methods.<br> * For more information check the official node documentation:<br> * {@link https://nodejs.org/docs/latest-v14.x/api/crypto.html} * @example D.crypto * @memberof D * @namespace D.crypto */ crypto: cryptoLibrary.cryptoLibrary(newConsole), /** * Get a predefined parameter during execution by its name. * Returns undefined in case the parameter was not provided to the context. * @example D.getParameter("name") * @memberof D * @function * @param {string} parameterName - Name of the parameter to get * @return {string|number|Object|undefined} - the value associated with the provided parameter name */ getParameter: contextParameterLibrary.getParameter, /** * Known Domotz Context Error types * @example D.errorType.AUTHENTICATION_ERROR * @memberof D * @readonly * @enum {ErrorType} */ errorType: errorTypes, /** * Domotz Variable Value Types * @example D.valueType.MONOTONE_RATE * @memberof D * @readonly * @enum {ValueType} */ valueType: valueTypes, /** * Failure callback in D (D.failure). * It can be present in any function in order to indicate a failure in the execution * @example D.failure(D.errorType.AUTHENTICATION_ERROR) * @memberof D * @function * @param {ErrorType} [errorType] - The type of error that caused the failure callback. Must be a member of D.errorType */ failure: null, /** * Html Parser Library * @example D.htmlParse() * @function * @param {string|Node|Node[]|Buffer} content - Markup to be loaded. * @param {CheerioOptions} [options] - Options for the created instance. * @param {boolean} [isDocument=true] - Allows parser to be switched to fragment mode. * @returns {CheerioAPI} - The loaded document */ htmlParse: require('cheerio').load, /** * Mathematical Utilities library * @example D.math * @namespace D.math * @memberof D */ math: { /** * Percentage Calculating Function * @function * @example * // returns 70 * D.math.percent(7, 10) * @param {number} actual - The actual number * @param {number} maximum - The maximum number * @returns {number} - The Percentage */ percent: function (actual, maximum) { return Math.round((10000.0 * parseInt(actual, 10)) / parseInt(maximum, 10)) / 100; }, }, /** * NodeJS Lodash Module * Javascript utility library that delivers modularity, performance and some extra features. * @example D._ * @memberof D * @external _ * @see {@link https://lodash.com/docs/4.17.15} */ _: require('lodash'), /** * Nodejs q Module * @private * @example D.q * @memberof D * @external q * @see {@link https://devdocs.io/q/} */ q: require('q'), /** * Wrapper for unsafe functions which can lead to crashing the agent or other potential problems if not used properly * @example D._unsafe * @memberof D * @namespace D._unsafe */ _unsafe: { buffer: bufferLibrary.bufferLibrary(newConsole), }, }; /** * Domotz Generic Context * @namespace DomotzGeneric * @extends D */ var DomotzGenericContext = Object.create(DomotzContext); /** * Success callback in D (D.success). * It must be present in validate, get_status or all custom action functions code (or their callbacks) * in order to indicate their successful execution * @example D.success() * @example D.success(table) * @example D.success(variables) * @example D.success(variables, table) * @memberof DomotzGeneric * @function * @param {Array.<Variable>} [variables] - The variables to return (dry run) or store * @param {driverTable} [table] - The custom driver table to return (dry run) or store */ DomotzGenericContext.success = null; /** * Creates a driver table for variable values visualization in a table format * @example D.createTable("My Table", [{"label": "Column A"}, {"label": "Column B", "unit": "%"}]) * @memberof DomotzGeneric * @function * @param {string} label - The Table Label * @param {Array.<ColumnHeader>} columnHeaders - The List of column header definitions * @readonly * @return {driverTable} - The Custom Driver Table object */ DomotzGenericContext.createTable = function (label, columnHeaders) { driverTable = tableLibrary.createTable(label, columnHeaders, newConsole); return driverTable; }; /** * Creates a custom driver variable to be sent in the D.success callback. * <br> This variable is suited for tracking a single key-value pair, if you want to * track tabular data, use {@link D.createTable} instead. * @example * // returns {"uid": "1a", "unit": "C", "value": 60, "label": "CPU Temperature"} * D.createVariable('1a', 'CPU Temperature', 60, 'C', D.valueType.NUMBER) * @memberof DomotzGeneric * @function * @readonly * @param {string} uid - The identifier of the variable. Must be Unique. Max 50 characters * <br> cannot be one of the following reserved words: "table", "column", "history" * @param {string} name - The Name/Label of the variable. Max 100 characters * @param {string} value - The Value of the variable. Max 500 characters * @param {string} unit - The Unit of measurement of the variable (eg %). Max 10 characters * @param {ValueType} valueType - The value type of the variable (used for display purposes) * @return {Variable} */ DomotzGenericContext.createVariable = function (uid, name, value, unit, valueType) { driverVariable = variableLibrary.createVariable(uid, name, value, unit, valueType, agentDriverSettings); return driverVariable; }; /** * Domotz Configuration Management Context * @namespace DomotzConfigurationManagement * @extends D */ var DomotzConfigurationManagementContext = Object.create(DomotzContext); /** * Success callback in D (D.success). * It must be present in the validate and backup functions (or their callbacks) * in order to indicate their successful execution * @memberof DomotzConfigurationManagement * @example D.success() * @example D.success(configuration) * @function * @param {ConfigurationBackup} [configuration] - The configuration to return (dry run) or store for backup */ DomotzConfigurationManagementContext.success = null; /** * Function createBackup * @memberof DomotzConfigurationManagement * @function * @param {ConfigurationBackup} configurationBackup - The backup object to be filled in and validated * @return {ConfigurationBackup} */ DomotzConfigurationManagementContext.createBackup = function (configurationBackup) { // maybe move to a library file var validatedBackup = {}; if (configurationBackup === undefined || configurationBackup === null) { throw Error('Invalid configuration backup object - it must not be null or undefined'); } validatedBackup.label = configurationBackup.label || 'Custom Driver Configuration Backup'; if (configurationBackup.running === undefined || configurationBackup.running === null || !(typeof configurationBackup.running === 'string')) { throw Error('Invalid running configuration backup content - it must be string and not ' + typeof configurationBackup.running); } else if (agentDriverSettings.max_config_backup_size < configurationBackup.running.length) { throw Error( 'Maximum running configuration backup size exceeded: allowed ' + agentDriverSettings.max_config_backup_size.toString() + ' bytes, provided ' + configurationBackup.running.length.toString() ); } else { validatedBackup.running = configurationBackup.running; } if (typeof configurationBackup.startup === 'string') { if (agentDriverSettings.max_config_backup_size < configurationBackup.startup.length) { throw Error( 'Maximum startup configuration backup size exceeded: allowed ' + agentDriverSettings.max_config_backup_size.toString() + ' bytes, provided ' + configurationBackup.startup.length.toString() ); } else { validatedBackup.startup = configurationBackup.startup; } } else if (configurationBackup.startup !== undefined || configurationBackup.startup !== null) { validatedBackup.startup = null; } else { throw Error( 'Invalid startup configuration backup content - it must be string, null or undefined and not ' + typeof configurationBackup.startup ); } if (configurationBackup.ignoredLines === null || configurationBackup.ignoredLines === undefined) { validatedBackup.ignoredLines = null; } else if (!Array.isArray(configurationBackup.ignoredLines)) { throw Error( 'Invalid ignored lines for configuration backup content - it must be string array, null or undefined and not ' + (typeof configurationBackup.ignoredLines) ) } else if (configurationBackup.ignoredLines.length > agentDriverSettings.max_ignored_lines) { throw Error("Too many ignored line regular expressions, max allowed number is " + agentDriverSettings.max_ignored_lines.toString()) } else { validatedBackup.ignoredLines = []; for (var i = 0; i < configurationBackup.ignoredLines.length; i++) { var line = configurationBackup.ignoredLines[i]; if (!(typeof(line) === "string")) { throw Error("A regex must be a string, and not " + typeof(line)) } else if (line.length > agentDriverSettings.max_ignored_line_len) { throw Error( 'Line ' + line + ' too long (=' + line.length.toString() + '), ' + 'max allowed length is ' + agentDriverSettings.max_ignored_line_len.toString() ); } else { validatedBackup.ignoredLines.push(line); } } } return validatedBackup; }; if (message.driverType === driverTypes.CONFIGURATION_MANAGEMENT) { return DomotzConfigurationManagementContext; } else if (message.driverType === driverTypes.GENERIC) { return DomotzGenericContext; } else { return DomotzGenericContext; } };