mylisabox/lisa-box

View on GitHub
lisa.js

Summary

Maintainability
D
2 days
Test Coverage
'use strict'
const EventEmitter = require('events')
const NOTIFICATION_TYPE = require('./api/utils/enums').NOTIFICATION_TYPE
const DEVICE_TYPE = require('./api/utils/enums').DEVICE_TYPE

module.exports = (function () {
  //private
  let app

  /**
   * Get native stack
   * @returns array of javascript calls
   */
  const getStack = function () {
    // Save original Error.prepareStackTrace
    const origPrepareStackTrace = Error.prepareStackTrace
    // Override with function that just returns `stack`
    Error.prepareStackTrace = (_, stack) => stack

    // Create a new `Error`, which automatically gets `stack`
    const err = new Error()
    // Evaluate `err.stack`, which calls our new `Error.prepareStackTrace`
    const stack = err.stack
    // Restore original `Error.prepareStackTrace`
    Error.prepareStackTrace = origPrepareStackTrace
    // Remove superfluous function call on stack
    stack.shift() // getStack --> Error
    return stack
  }

  /**
   * Get path of the current plugin
   * @returns path
   */
  const getCaller = () => {
    const stack = getStack()
    stack.shift()
    let obj
    for (let i = 0; i < stack.length; i++) {
      obj = stack[i]
      if (obj.getFileName().toLowerCase().indexOf('plugin-') !== -1) {
        break
      }
    }
    // Return caller's caller
    return obj.getFileName()
  }

  /**
   * Get name of the current plugin
   * @returns string name
   */
  const getCurrentPlugin = () => {
    const pathString = getCaller()
    const parts = pathString.split('/')
    let part = parts.find(part => part.indexOf('lisa-plugin') !== -1)
    if (!part) {
      part = 'unknown'
    }
    const name = part.replace(/lisa\-/, '').replace(/plugin\-/, '').toCamelCase()
    return app.packs.pluginsManager.plugins[name] ? app.packs.pluginsManager.plugins[name].fullName : 'unknown'
  }

  return class LISA extends EventEmitter {
    get NOTIFICATION_TYPE() {
      return NOTIFICATION_TYPE
    }

    get DEVICE_TYPE() {
      return DEVICE_TYPE
    }

    constructor(currentApp) {
      super()
      app = currentApp
    }

    toCamelCase(input) {
      return input.toCamelCase()
    }

    getRooms() {
      return app.orm.Room.findAll().then(rooms => {
        return Promise.resolve(rooms.map(room => room.toJSON()))
      })
    }

    createRoom(name) {
      return app.orm.Room.create({name: name}).then(room => {
        return Promise.resolve(room.toJSON())
      })
    }

    createOrUpdateDevices(device, criteria) {
      const plugin = getCurrentPlugin()
      //app.log.debug(plugin)
      let promise

      if (Array.isArray(device)) {
        const toCreate = device.filter(element => !element.id).map(device => {
          device.pluginName = plugin
          return device
        })
        const toUpdate = device.filter(element => element.id)
        const todo = []

        if (toCreate.length > 0) {
          todo.push(app.orm.Device.bulkCreate(toCreate))
        }
        if (toUpdate.length > 0) {
          for (const deviceToUpdate of toUpdate) {
            todo.push(this.createOrUpdateDevices(deviceToUpdate))
          }
        }
        promise = Promise.all(todo)
      }
      else {
        device.pluginName = plugin
        if (device.id) {
          promise = app.orm.Device.update(device, {
            where: {
              id: device.id
            }
          })
        }
        else if (criteria) {
          criteria.pluginName = plugin
          promise = app.orm.Device.update(device, {
            where: criteria
          })
        }
        else {
          promise = app.orm.Device.create(device)
        }
      }

      return promise.then(device => {
        if (Array.isArray(device)) {
          return device.map(item => {
            if (item.toRawData) {
              return item.toRawData()
            }
            return item
          })
        }
        else {
          if (device.toRawData) {
            return device.toRawData()
          }
          return device
        }
      })
    }

    /**
     *
     * @param criteria to retrieve specific devices
     * @returns Promise
     */
    findDevices(criteria) {
      criteria = criteria || {}
      const plugin = getCurrentPlugin()
      //app.log.debug(plugin)
      criteria.pluginName = plugin

      const promise = criteria.id ? app.orm.Device.find({
        where: criteria
      }) : app.orm.Device.findAll({
        where: criteria
      })

      return promise.then(devices => {
        if (Array.isArray(devices)) {
          return devices.map(device => device.toRawData())
        }
        else {
          return devices.toRawData()
        }
      })
    }

    /**
     * Send notification to the user(s)
     * @param to @optional user id to send the notif to
     * @param title of the notif
     * @param type
     * @param desc of the notif
     * @param image of the notif
     * @param defaultAction of the notif
     * @param action of the notif
     * @param lang of the notif
     * @returns Promise - notif data
     */
    sendNotification(to, title, type, desc, image, defaultAction, action, lang) {
      const plugin = getCurrentPlugin()
      return app.services.NotificationService.sendNotification(to, plugin, title, type, desc, image, defaultAction,
        action, lang, 'default').then(notification => notification.toJSON())
    }

    /**
     * Retrieve plugin preferences
     * @returns {Promise} preferences or error
     */
    getPreferences() {
      const plugin = getCurrentPlugin()
      app.log.debug(plugin)
      return app.orm.Preference.findById(plugin + '_prefs').then(preferences => {
        return preferences ? preferences.value : {}
      })
    }

    /**
     * Set plugin preferences
     * @param preferences to save
     * @returns {Promise} saved preferences or error
     */
    setPreferences(preferences) {
      const plugin = getCurrentPlugin()
      app.log.debug(plugin)
      return app.orm.Preference.upsert({
        key: plugin + '_prefs',
        value: preferences
      }).then(() => {
        return preferences
      })
    }

    addChatBot(botId, botData) {
      const plugin = getCurrentPlugin()
      botData.pluginName = plugin
      return app.services.ChatBotService.addBot(botId, botData).then(chatBot => Promise.resolve(chatBot.toJSON()))
    }

    getChatBot(botId = null) {
      const plugin = getCurrentPlugin()
      const where = {
        pluginName: plugin
      }
      if (botId) {
        where.name = botId
      }
      return app.orm.ChatBot.findAll({
        where: where
      }).then(chatBots => Promise.resolve(chatBots.map(bot => bot.toJSON())))
    }

    updateChatBot(botId, botData) {
      const plugin = getCurrentPlugin()
      botData.pluginName = plugin
      return app.services.ChatBotService.updateBot(botId, botData).then(_ => Promise.resolve())
    }

    deleteChatBot(botId) {
      //const plugin = getCurrentPlugin()
      return app.services.ChatBotService.deleteBot(botId).then(_ => Promise.resolve())
    }

    get log() {
      const getArguments = (args) => {
        const plugin = getCurrentPlugin()
        const mainArguments = Array.prototype.slice.call(args)
        return [plugin + ':'].concat(mainArguments)
      }
      const logger = app.config.log.pluginLogger
      return {
        debug: function () {
          logger.debug(JSON.stringify(getArguments(arguments)))
        },
        info: function () {
          logger.info(JSON.stringify(getArguments(arguments)))
        },
        error: function () {
          logger.error(JSON.stringify(getArguments(arguments)))
        },
        silly: function () {
          logger.silly(JSON.stringify(getArguments(arguments)))
        },
        verbose: function () {
          logger.verbose(JSON.stringify(getArguments(arguments)))
        },
        warn: function () {
          logger.warn(JSON.stringify(getArguments(arguments)))
        }
      }
    }

    get _() {
      return app._
    }

    get i18n() {
      return app._
    }

    get bonjour() {
      return app.bonjour
    }

    get mdns() {
      return app.mdns
    }

    get serialPort() {
      return app.serialPort
    }

    get ir() {
      return {
        send: (remote, action) => {
          return app.services.IRService.send(remote, action)
        }
      }
    }
  }
})()