wildduck/lib/plugins.js
2017-10-26 14:57:19 +03:00

144 lines
4.1 KiB
JavaScript

'use strict';
const config = require('wild-config');
const pathlib = require('path');
const log = require('npmlog');
const db = require('./db');
const WD_PATH = pathlib.join(__dirname, '..');
const CONFIG_PATH = config.configDirectory || WD_PATH;
const hooks = new Map();
class PluginInstance {
constructor(key, config) {
this.db = db;
this.key = key;
this.config = config || {};
this.logger = {};
['silly', 'verbose', 'info', 'http', 'warn', 'error', 'debug', 'err'].forEach(level => {
this.logger[level] = (...args) => {
switch (level) {
case 'debug':
level = 'verbose';
break;
case 'err':
level = 'error';
break;
}
log[level]('[' + key + ']', ...args);
};
});
}
addHook(hook, handler) {
hook = (hook || '')
.toString()
.replace(/\s+/g, '')
.toLowerCase();
if (!hook) {
return;
}
if (!hooks.has(hook)) {
hooks.set(hook, []);
}
hooks.get(hook).push({ plugin: this, handler });
}
init(done) {
if (!this.config.path) {
this.logger.debug('Plugin path not provided, skipping');
return setImmediate(done);
}
try {
let pluginPath = this.config.path.replace(/\$WD/g, WD_PATH).replace(/\$CONFIG/g, CONFIG_PATH);
this.module = require(pluginPath); //eslint-disable-line global-require
} catch (E) {
this.logger.error('Failed to load plugin. %s', E.message);
return setImmediate(done);
}
if (typeof this.module.init !== 'function') {
this.logger.debug('Init method not found');
return setImmediate(done);
}
try {
return this.module.init(this, err => {
if (err) {
this.logger.error('Initialization resulted with an error. %s', err.message);
} else {
this.logger.debug('Plugin "%s" initialized', this.module.title || this.key);
}
return setImmediate(done);
});
} catch (E) {
this.logger.error('Failed executing init method. %s', E.message);
return setImmediate(done);
}
}
}
module.exports.init = next => {
let keys = Object.keys(config.plugins || {});
let pos = 0;
let loadNextPlugin = () => {
if (pos >= keys.length) {
return setImmediate(next);
}
let key = keys[pos++];
if (!config.plugins[key].enabled) {
return setImmediate(loadNextPlugin);
}
let plugin = new PluginInstance(key, config.plugins[key]);
plugin.init(loadNextPlugin);
};
setImmediate(loadNextPlugin);
};
module.exports.runHooks = (hook, ...args) => {
let next = args.pop();
hook = (hook || '')
.toString()
.replace(/\s+/g, '')
.toLowerCase();
if (!hook || !hooks.has(hook)) {
return setImmediate(next);
}
let handlers = hooks.get(hook);
let pos = 0;
let processHandler = () => {
if (pos >= handlers.length) {
return setImmediate(next);
}
let entry = handlers[pos++];
let returned = false;
try {
entry.handler(...args, err => {
if (returned) {
return;
}
returned = true;
if (err) {
entry.plugin.logger.error('Failed processing hook %s. %s', hook, err.message);
}
setImmediate(processHandler);
});
} catch (E) {
if (returned) {
return;
}
returned = true;
entry.plugin.logger.error('Failed processing hook %s. %s', hook, E.message);
setImmediate(processHandler);
}
};
setImmediate(processHandler);
};