@iobroker/plugin-base
Version:
Base module for plugins for js-controller and adapters
241 lines (218 loc) • 8.11 kB
JavaScript
/// <reference path="./types.d.ts" />
const NamespaceLogger = require('./NamespaceLogger');
/**
* Base class for ioBroker Plugins
*/
class PluginBase {
/**
* Constructor for Plugin class
* This method is called by js-controller/adapter process internally when initializing the plugin.
*
* @param {import("@iobroker/plugin-base/types").PluginSettings} settings
*/
constructor(settings) {
this.pluginScope = settings.pluginScope;
this.parentNamespace = settings.parentNamespace;
this.pluginNamespace = settings.pluginNamespace;
this.log = new NamespaceLogger(settings.pluginLogNamespace, settings.log);
this.iobrokerConfig = settings.iobrokerConfig;
this.parentPackage = settings.parentPackage || {};
this.settings = settings;
this.objectsDb = null;
this.statesDb = null;
this.isActive = false;
this.SCOPES = {
'ADAPTER': 'adapter',
'CONTROLLER': 'controller'
};
}
/**
* Method for Plugin developer to initialize his Plugin
*
* @param {Record<string, any>} pluginConfig plugin configuration from config files
* @return {Promise<void>} resolves if init was successful else rejects
*/
init(pluginConfig) {
// Implement in your Plugin instance if needed
return Promise.reject(new Error('Not implemented'));
}
/**
* Method which is called on a clean end of the process to pot. clean up used resources
*
* @return {boolean} The return value indicates if the exit was successful. If no action needs to be taken, you should return true.
*/
destroy() {
// Implement in your Plugin instance if needed
return true;
}
/**
* Get a State from State DB
*
* @param {string} id id of the state to retrieve
* @return {ReturnType<ioBroker.Adapter["getStateAsync"]>} Promise with error or result
*/
getState(id) {
if (!this.statesDb) {
return Promise.reject(new Error('States Database not initialized.'));
}
return this.statesDb.getStateAsync(id);
}
/**
* Set a State in State DB
*
* @param {string} id id of the state to set
* @param {Partial<ioBroker.State>} state state value to set
* @return {Promise<ioBroker.State | null | undefined>} Promise with error or result
*/
setState(id, state) {
if (!this.statesDb) {
return Promise.reject(new Error('States Database not initialized.'));
}
return this.statesDb.setStateAsync(id, state);
}
/**
* Get an Object from Objects DB
*
* @param {string} id id of the object to retrieve
* @return {Promise<ioBroker.Object | null | undefined>} Promise with result or error
*/
getObject(id) {
if (!this.objectsDb) {
return Promise.reject(new Error('Objects Database not initialized.'));
}
return this.objectsDb.getObjectAsync(id);
}
/**
* Set an Object in Objects DB
*
* @param {string} id id of the object to set
* @param {ioBroker.Object} obj object to set
* @return {ReturnType<ioBroker.Adapter["setObjectAsync"]>} Promise with error or result
*/
setObject(id, obj) {
if (!this.objectsDb) {
return Promise.reject(new Error('Objects Database not initialized.'));
}
return this.objectsDb.setObjectAsync(id, obj);
}
/**
* Set/Extend an Object in Objects DB
*
* @param {string} id id of the object to set/extend
* @param {object} obj object to set
* @return {ReturnType<ioBroker.Adapter["extendObjectAsync"]>} Promise with result or error
*/
extendObject(id, obj) {
if (!this.objectsDb) {
return Promise.reject(new Error('Objects Database not initialized.'));
}
return this.objectsDb.extendObjectAsync(id, obj);
}
/****************************************
* Internal methods!!
****************************************/
/**
* @internal
* Set the Active flag for the plugin
*
* @param {boolean} active true/false if active
*/
async setActive(active) {
this.isActive = !!active;
await this.setState(this.pluginNamespace + '.enabled', {
val: !!active,
ack: true,
from: this.pluginNamespace
});
}
/**
* @internal
* Set the objects and states database to be used internally
* This method is called by js-controller/adapter process internally when initializing the plugin.
*
* @param {any} objectsDb objects DB instance
* @param {any} statesDb states DB instance
*/
setDatabase(objectsDb, statesDb) {
this.objectsDb = objectsDb;
this.statesDb = statesDb;
}
/**
* @internal
* Initialize plugin, internal method
*
* @param {Record<string, any>} pluginConfig plugin configuration from config files
* @param {Record<string, any>} parentConfig io-package from parent module where plugin is used in
*/
async initPlugin(pluginConfig, parentConfig) {
if (!pluginConfig) {
throw new Error('No configuration for plugin');
}
this.parentIoPackage = parentConfig;
let pluginEnabledState;
try {
await this.extendObject(this.pluginNamespace, {
type: 'folder',
common: {
name: 'Plugin States',
},
native: {}
});
await this.extendObject(`${this.pluginNamespace}.enabled`, {
type: 'state',
common: {
name: 'Plugin - enabled',
type: 'boolean',
read: true,
write: true,
role: 'value'
},
native: {}
});
pluginEnabledState = await this.getState(`${this.pluginNamespace}.enabled`);
} catch {
// ignore
}
if (pluginEnabledState && typeof pluginEnabledState.val !== 'object' && pluginEnabledState.val !== undefined) {
// We already have a enabled flag state, use it
return this._initialize(pluginConfig, !!pluginEnabledState.val);
}
// We have first start and no enabled flag is set
if (this.pluginScope === this.SCOPES.ADAPTER && parentConfig && parentConfig.common && parentConfig.common.host) {
// We check if the host has a sentry enabled flag
const hostNamespace = this.pluginNamespace.replace(new RegExp('system\.adapter\.' + parentConfig.common.name + '\.[0-9]+\.'), 'system.host.' + parentConfig.common.host + '.');
let hostState;
try {
hostState = await this.getState(`${hostNamespace}.enabled`);
} catch {
// ignore
}
if (hostState && typeof hostState.val !== 'object' && hostState.val !== undefined) {
// We simply use the host enabled flag state
return this._initialize(pluginConfig, !!hostState.val);
}
}
this._initialize(pluginConfig, pluginConfig.enabled === undefined ? true : !!pluginConfig.enabled);
}
/**
* @internal
* @param {Record<string, any>} pluginConfig
* @param {string | boolean} activate
*/
async _initialize(pluginConfig, activate) {
if (activate) {
this.log.debug(`Initialize Plugin (enabled=${activate})`);
pluginConfig.enabled = activate;
try {
await this.init(pluginConfig);
await this.setActive(true);
} catch (e) {
await this.setActive(false);
}
} else {
this.log.debug(`Do not initialize Plugin (enabled=${activate})`);
await this.setActive(false);
}
}
}
module.exports = PluginBase;