enigma-bbs/core/module_util.js
Bryan Ashby a7c0f2b7b0 * Add FileBaseFilters
* Add HTTP(S) file web server with temp URLs
* Get temp web d/l from file list
* Add File area filter editor (all file area stuff will be rename to file "base" later)
* Concept of "listening servers" vs "login servers"
* Ability to get servers by their package name
* New MCI: %FN: File Base active filter name
* Some ES6 updates
* VC resetInitialFocus() to set focus to explicit/detected initial focus field
* Limit what is dumped out when logging form data
2016-10-24 21:49:45 -06:00

99 lines
2.4 KiB
JavaScript

/* jslint node: true */
'use strict';
// ENiGMA½
const Config = require('./config.js').config;
// deps
const fs = require('fs');
const paths = require('path');
const _ = require('lodash');
const assert = require('assert');
const async = require('async');
// exports
exports.loadModuleEx = loadModuleEx;
exports.loadModule = loadModule;
exports.loadModulesForCategory = loadModulesForCategory;
function loadModuleEx(options, cb) {
assert(_.isObject(options));
assert(_.isString(options.name));
assert(_.isString(options.path));
const modConfig = _.isObject(Config[options.category]) ? Config[options.category][options.name] : null;
if(_.isObject(modConfig) && false === modConfig.enabled) {
const err = new Error(`Module "${options.name}" is disabled`);
err.code = 'EENIGMODDISABLED';
return cb(err);
}
//
// Modules are allowed to live in /path/to/<moduleName>/<moduleName>.js or
// simply in /path/to/<moduleName>.js. This allows for more advanced modules
// to have their own containing folder, package.json & dependencies, etc.
//
let mod;
let modPath = paths.join(options.path, `${options.name}.js`); // general case first
try {
mod = require(modPath);
} catch(e) {
if('MODULE_NOT_FOUND' === e.code) {
modPath = paths.join(options.path, options.name, `${options.name}.js`);
try {
mod = require(modPath);
} catch(e) {
return cb(e);
}
} else {
return cb(e);
}
}
if(!_.isObject(mod.moduleInfo)) {
return cb(new Error('Module is missing "moduleInfo" section'));
}
if(!_.isFunction(mod.getModule)) {
return cb(new Error('Invalid or missing "getModule" method for module!'));
}
return cb(null, mod);
}
function loadModule(name, category, cb) {
const path = Config.paths[category];
if(!_.isString(path)) {
return cb(new Error(`Not sure where to look for "${name}" of category "${category}"`));
}
loadModuleEx( { name : name, path : path, category : category }, function loaded(err, mod) {
return cb(err, mod);
});
}
function loadModulesForCategory(category, iterator, complete) {
fs.readdir(Config.paths[category], (err, files) => {
if(err) {
return iterator(err);
}
const jsModules = files.filter(file => {
return '.js' === paths.extname(file);
});
async.each(jsModules, (file, next) => {
+ loadModule(paths.basename(file, '.js'), category, (err, mod) => {
iterator(err, mod);
return next();
});
}, err => {
if(complete) {
return complete(err);
}
});
});
}