Advertisement
Guest User

Untitled

a guest
Apr 21st, 2018
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2.  
  3. const fs       = require('fs');
  4. const path     = require('path');
  5. const chokidar = require('chokidar');
  6. const utils    = require('./utils.js');
  7.  
  8. class PluginHandler {
  9.   constructor(dir) {
  10.     this.dir     = dir;
  11.     this.plugins = {};
  12.  
  13.     // handle uncaught exceptions
  14.     process.on('uncaughtException', err => {
  15.       utils.error(err.stack);
  16.     });
  17.  
  18.     // read files in plugin directory
  19.     let cwd = __dirname.split(/\\/g).join('/');
  20.     let files = this.getFilesSync(dir)
  21.       .map(file => `${cwd}/${file}`);
  22.  
  23.     // watch directory for changes
  24.     this.watch = chokidar.watch(dir, {persistent:true});
  25.     this.watch.on('ready', () => {
  26.       this.watch.on('error', utils.error);
  27.       this.watch.on('add', path => {this.newPlugin(path)});
  28.       this.watch.on('change', path => {this.reloadPlugin(path)});
  29.       this.watch.on('unlink', path => {this.removePlugin(path)});
  30.     });
  31.  
  32.     // load plugins
  33.     files.forEach(file => {
  34.       this.addPlugin(file, true);
  35.     });
  36.     utils.log(`Loaded ${files.length} plugins.`);
  37.   }
  38.  
  39.   /**
  40.    * Give info to corresponding plugin or alias
  41.    * @param {Object} info the message info
  42.    */
  43.   apply(info) {
  44.     if (info.command in this.plugins) {
  45.       let plugin = this.plugins[info.command];
  46.       if ('action' in plugin.module) plugin.module.action(info);
  47.     } else {
  48.       let aliases = Object.values(this.plugins)
  49.         .map(plugin => {
  50.           //console.log('applying plugin:', JSON.stringify(plugin, null, 2));
  51.           return (plugin.module && 'aliases' in plugin.module) ?
  52.             plugin.module.aliases.map(name => {
  53.               return {name: name, plugin: plugin}}) : []
  54.         });
  55.       aliases = {names: aliases, executed: false}
  56.       aliases.names.forEach(names => {
  57.         names.forEach(alias => {
  58.           if (aliases.executed) return;
  59.           if (alias.name === info.command) {
  60.             let plugin = alias.plugin;
  61.             if ('action' in plugin.module) plugin.module.action(info);
  62.             aliases.executed = true;
  63.           }
  64.         });
  65.       });
  66.     }
  67.   }
  68.  
  69.   /**
  70.    * Read a dir for all of its files synchronously
  71.    * @param {String} dir the directory to scan for files
  72.    * @return {Array} the list of absolute paths to the files
  73.    */
  74.   getFilesSync(dir) {
  75.     const cwd = __dirname.split(/\\/g).join('/');
  76.     const flatten = arr => arr.reduce((acc, val) =>
  77.       acc.concat(Array.isArray(val) ? flatten(val) : val), []);
  78.     return flatten(fs.readdirSync(dir)
  79.       .map(file => fs.statSync(path.join(dir, file)).isDirectory()
  80.         ? this.getFilesSync(path.join(dir, file))
  81.         : path.join(dir, file).replace(/\\/g, '/')))
  82.   }
  83.  
  84.   /**
  85.    * Get the plugin name of a path
  86.    * @param {String} path the plugin path
  87.    * @return {String} abstracted plugin name
  88.    */
  89.   getName(path) {
  90.     let name = path.split('/')
  91.       .slice(-1)[0]
  92.       .split('.')
  93.       .slice(0,-1)
  94.       .join('.');
  95.     return name;
  96.   }
  97.  
  98.   /**
  99.    * Get a Plugin by its path
  100.    * @param {String} path the plugin path
  101.    * @return {Object Nullbale} the plugin
  102.    */
  103.   getByPath(path) {
  104.     let name = this.getName(path.replace(/\\/g, '/'));
  105.     return (name in this.plugins) ? this.plugins[name] : null;
  106.   }
  107.  
  108.   /**
  109.    * Create a new plugin place-holder
  110.    * @param {String} path the path to load the plugin
  111.    * @param {Boolean} quiet whether or not to print action
  112.    */
  113.   newPlugin(path, quiet) {
  114.     if (!path.endsWith('.js')) return;
  115.     let plugin = {
  116.       name: this.getName(path),
  117.       path: path.startsWith('./') ? path.substring(2) : path
  118.     };
  119.     if (!plugin.path.startsWith(__dirname.split('\\')[0]))
  120.       plugin.path = __dirname.split('\\')
  121.         .concat(
  122.           plugin.path
  123.             .split(plugin.path.indexOf('\\') > -1 ? '\\' : '/')
  124.         ).join('/');
  125.     this.plugins[plugin.name] = plugin;
  126.     if (!quiet) utils.log(`Created plugin [${plugin.name}]`);
  127.     return plugin;
  128.   }
  129.  
  130.   /**
  131.    * Load the action through the plugin place-holder
  132.    * @param {String} path the path of the plugin
  133.    * @param {Boolean} quiet whether or not to print action
  134.    */
  135.   addPlugin(path, quiet) {
  136.     let plugin = this.newPlugin(path, quiet);
  137.     if (!plugin) return;
  138.     if (!quiet) utils.log(`Adding plugin [${plugin.name}]`);
  139.     this.plugins[plugin.name].module = require(plugin.path)
  140.   }
  141.  
  142.   /**
  143.    * Remove the plugin from the handlers
  144.    * @param {String} path the path of the plugin
  145.    * @param {Boolean} quiet whether or not to print action
  146.    */
  147.   removePlugin(path, quiet) {
  148.     let plugin = this.getByPath(path);
  149.     if (!plugin) return;
  150.     if (plugin.name in this.plugins) {
  151.       if (!quiet) utils.log(`Removing plugin [${plugin.name}]`);
  152.       delete require.cache[require.resolve(plugin.path)];
  153.       delete this.plugins[plugin.name];
  154.       plugin = undefined;
  155.     }
  156.   }
  157.  
  158.   /**
  159.    * Reload action of plugin through place-holder
  160.    * @param {String} path the path to load the plugin
  161.    * @param {Boolean} quiet whether or not to print action
  162.    */
  163.   reloadPlugin(path, quiet) {
  164.     let plugin = this.getByPath(path);
  165.     if (!plugin) return;
  166.     if (!quiet)
  167.       utils.log(`Reloading plugin [${plugin.name}]`);
  168.     delete require.cache[require.resolve(plugin.path)];
  169.     plugin.module = require(plugin.path);
  170.   }
  171. };
  172.  
  173. module.exports = PluginHandler;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement