Source: modules.js

const reload = require('require-reload')(require);
const path = require('path');

/**
 * Module Base class
 */
class BotModule {
  /**
   * Instantiates a Module
   */
  constructor() {
    /**
     * The current FocaBotCore instance
     * @deprecated
     * @type {FocaBotCore}
     */
    this.engine = global.Core; // backwards compatibility
    /** Discordie client */
    this.bot = global.Core.bot;
    /**
     * A reference to the PermissionsManager.
     * @deprecated
     * @type {PermissionsManager}
     */
    this.permissions = global.Core.permissions;
    /** Registered Commands */
    this.commands = [];
  }

  /**
   * Registers a command.
   * @param {string} name - Command name.
   * @param {object} options - Command options.
   * @param {function} func - Command handler.
   * @returns {BotCommand}
   * @see {BotCommand}
   */
  registerCommand(name, options, func) {
    try {
      const command = Core.commands.register(name, options, func);
      this.commands.push(command);
      return command;
    } catch (e) {
      Core.log(e, 2);
      return false;
    }
  }

  shutdown() {
    if (typeof this.unload === 'function') this.unload();
    Core.commands.unregister(this.commands);
  }
}

/**
 * Manages the modules.
 */
class ModuleManager {
  constructor() {
    /** Currently loaded modules */
    this.loaded = {};
    this.modulePath = Core.settings.modulePath || path.join(__dirname, '../modules');
  }

  /**
   * Loads the specified modules.
   * @param {string[]} modules - Modules to load
   */
  load(modules) {
    const m = (typeof modules === 'string') ? [modules] : modules;
    if (!m.forEach) throw new Error('This function only accepts strings or arrays.');
    m.forEach((module) => {
      try {
        const Module = reload(path.join(this.modulePath, module));
        this.loaded[module] = new Module();
        if (typeof this.loaded[module].init === 'function') this.loaded[module].init();
      } catch (e) {
        Core.log(e, 2);
      }
    });
  }

  /**
   * Unloads the specified modules.
   * @param {string[]} modules - Modules to unload
   */
  unload(modules) {
    const m = (typeof modules === 'string') ? [modules] : modules;
    if (!m.forEach) throw new Error('This function only accepts strings or arrays.');
    m.forEach((module) => {
      try {
        this.loaded[module].shutdown();
        delete this.loaded[module];
      } catch (e) {
        Core.log(e, 2);
      }
    });
  }

  /**
   * Reloads the specified modules.
   * @param {string[]} modules - Modules to load
   */
  reload(modules) {
    this.unload(modules);
    this.reload(modules);
  }
}

module.exports = ModuleManager;
global.BotModule = BotModule;