mylisabox/lisa-plugin

View on GitHub
index.js

Summary

Maintainability
A
0 mins
Test Coverage
import {isPlainObject, merge, mapValues} from 'lodash-es';

class Plugin {
  /**
   * @constructor
   * @param lisa L.I.S.A. instance
   * @param plugin.api The api entities defined in this plugin (api/ folder)
   * @param plugin.config The plugin configuration (config/ folder)
   * @param plugin.pkg The plugin package.json
   *
   * Instantiate the Plugin and set some initial properties. All Plugins
   * should implement their own constructors, and call super(lisa, plugin) with
   * their own definitions. Implementing application logic in the plugin
   * constructor is not recommended.
   */
  constructor(lisa, plugin) {
    this.lisa = lisa;

    if (!plugin) {
      throw new Error('lisa-plugin should be extend and plugin config should be set on constructor');
    }

    plugin = merge({
      config: {},
      drivers: {},
      bots: {},
    }, plugin);

    Object.defineProperties(this, {
      pkg: {
        value: Object.freeze(plugin.pkg),
        enumerable: false,
      },
      config: {
        value: plugin.config,
        enumerable: false,
      },
      bots: {
        value: plugin.bots,
        enumerable: false,
      },
    });
    this.drivers = this._bindMethods(lisa, plugin, 'drivers');
  }

  /**
   * Bind the context of API resource methods.
   * @param lisa
   * @param plugin
   * @param resource
   * @returns {Object}
   * @private
   */
  _bindMethods(lisa, plugin, resource) {
    return mapValues(plugin[resource], (Resource, resourceName) => {
      if (isPlainObject(Resource)) {
        throw new Error(`${resourceName} should be a class. It is a regular object`);
      }

      return new Resource(lisa, this);
    });
  }

  /**
   * Initialisation of your plugin
   * Called once, when plugin is loaded
   * @returns Promise
   */
  init() {
    const driversInit = [];
    for (const driverName of Object.keys(this.drivers)) {
      driversInit.push(this.drivers[driverName].init());
    }
    return Promise.all(driversInit);
  }

  /**
   * Called when
   * @param action to execute
   * @param infos context of the action
   * @return Promise
   */
  interact(action, infos) {
    return Promise.resolve();
  }

  /**
   * Unload this Plugin. This method will instruct the plugin to perform
   * any necessary cleanup with the expectation that the app will stop or reload
   * soon thereafter.
   */
  unload() {
    const driversUnload = [];
    for (const driver of this.drivers) {
      driversUnload.push(driver.unload());
    }
    return Promise.all(driversUnload);
  }

  emit(...args) {
    return this.lisa.emit(...args);
  }

  once(...args) {
    return this.lisa.once.apply(...args);
  }

  on(...args) {
    return this.lisa.once(...args);
  }

  after(...args) {
    return this.lisa.after.apply(...args);
  }

  /**
   * Expose the application's logger directly on the Plugin for convenience.
   */
  get log() {
    return this.lisa.log;
  }

  /**
   * Return the name of this Plugin. By default, this is the name of the
   * npm module (in package.json). This method can be overridden for plugins
   * which do not follow the "lisa-" prefix naming convention.
   *
   * @return String
   */
  get name() {
    return this.pkg.name.replace(/lisa-/, '').replace(/plugin-/, '').toCamelCase();
  }

  /**
   * Return the name of this Plugin. By default, this is the name of the
   * npm module (in package.json).
   *
   * @return String
   */
  get fullName() {
    return this.pkg.name;
  }

  /**
   * Return the version of this Plugin. By default, this is the version of the
   * npm module (in package.json).
   *
   * @return String
   */
  get version() {
    return this.pkg.version;
  }
}

class Driver {
  constructor(lisa, plugin) {
    this.lisa = lisa;
    this.plugin = plugin;
  }

  /**
   * Expose the application's logger directly on the Plugin for convenience.
   */
  get log() {
    return this.lisa.log;
  }

  get _() {
    return this.lisa._;
  }

  get i18n() {
    return this.lisa._;
  }

  /**
   * Init the driver, call once when driver is loaded
   * @returns {Promise}
   */
  async init() {
    return Promise.resolve();
  }

  /**
   * UI form submitted by the user and need to be saved
   * @param deviceData from the UI form
   * @returns {Promise}
   */
  async saveDevice(deviceData) {
    return this.lisa.createOrUpdateDevices(deviceData);
  }

  /**
   * Retrieve list of available devices
   * @returns {Promise.<Array>}
   */
  async getDevices() {
    return Promise.resolve([]);
  }

  /**
   * Data required by front UI
   * @param devices to fill data
   * @returns {Promise}
   */
  async getDevicesData(devices) {
    return Promise.resolve(devices);
  }

  /**
   * Data required by front UI
   * @param device to fill data
   * @returns {Promise}
   */
  async getDeviceData(device) {
    const data = await this.getDevicesData([device]);
    return Promise.resolve(data[0]);
  }

  /**
   * Trigger default action for given device
   * @param device to trigger
   * @returns {Promise}
   */
  async triggerDevice(device) {
    return Promise.resolve(device);
  }

  /**
   * Set new value to a device
   * @param device who has changed
   * @param key of the changed value
   * @param newValue
   * @returns {Promise}
   */
  async setDeviceValue(device, key, newValue) {
    return Promise.resolve();
  }

  /**
   * Set new value to multiple devices at once
   * @param devices who has changed
   * @param key of the changed value
   * @param newValue
   * @returns Promise
   */
  async setDevicesValue(devices, key, newValue) {
    return Promise.resolve();
  }

  async unload() {
    return Promise.resolve();
  }
}

export {Driver, Plugin};