From 949404cd1aad8492ae0338130f16054adfa38ab7 Mon Sep 17 00:00:00 2001 From: Neel Kamath Date: Sun, 13 May 2018 16:37:56 +0530 Subject: Prevent fucking shit up --- server/src/managers/imports-manager.js | 148 +++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 server/src/managers/imports-manager.js (limited to 'server/src/managers/imports-manager.js') diff --git a/server/src/managers/imports-manager.js b/server/src/managers/imports-manager.js new file mode 100644 index 0000000..d8b2144 --- /dev/null +++ b/server/src/managers/imports-manager.js @@ -0,0 +1,148 @@ +/** + * Import managment base, used to load commands/protocol and configuration objects + * + * Version: v2.0.0 + * Developer: Marzavec ( https://github.com/marzavec ) + * License: WTFPL ( http://www.wtfpl.net/txt/copying/ ) + * + */ + +const read = require('readdir-recursive'); +const path = require('path'); + +class ImportsManager { + /** + * Create a `ImportsManager` instance for (re)loading classes and config + * + * @param {Object} core reference to the global core object + * @param {String} base executing directory name; __dirname + */ + constructor (core, base) { + this._core = core; + this._base = base; + + this._imports = {}; + this._optionalConfigs = {}; + } + + /** + * Pull core reference + * + * @type {Object} readonly + */ + get core () { + return this._core; + } + + /** + * Pull base path that all imports are required in from + * + * @type {String} readonly + */ + get base () { + return this._base; + } + + /** + * Pull optional (none-core) config options + * + * @type {Object} + */ + get optionalConfigs () { + return Object.assign({}, this._optionalConfigs); + } + + /** + * Initialize this class and start loading target directories + * + */ + init () { + let errorText = ''; + ImportsManager.load_dirs.forEach(dir => { + errorText += this.loadDir(dir); + }); + + return errorText; + } + + /** + * Gather all js files from target directory, then verify and load + * + * @param {String} dirName The name of the dir to load, relative to the _base path. + */ + loadDir (dirName) { + const dir = path.resolve(this._base, dirName); + + let errorText = ''; + try { + read.fileSync(dir).forEach(file => { + const basename = path.basename(file); + if (basename.startsWith('_') || !basename.endsWith('.js')) return; + + let imported; + try { + imported = require(file); + } catch (e) { + let err = `Unable to load modules from ${dirName} (${path.relative(dir, file)})\n${e}`; + errorText += err; + console.error(err); + return errorText; + } + + if (imported.configs) { + imported.configs.forEach(config => { + this._optionalConfigs[config.name] = config; + }); + } + + if (!this._imports[dirName]) { + this._imports[dirName] = {}; + } + + this._imports[dirName][file] = imported; + }); + } catch (e) { + let err = `Unable to load modules from ${dirName}\n${e}`; + errorText += err; + console.error(err); + return errorText; + } + + return errorText; + } + + /** + * Unlink references to each loaded module, pray to google that gc knows it's job, + * then reinitialize this class to start the reload + * + * @param {String} dirName The name of the dir to load, relative to the _base path. + */ + reloadDirCache (dirName) { + Object.keys(this._imports[dirName]).forEach((mod) => { + delete require.cache[require.resolve(mod)]; + }); + + return this.init(); + } + + /** + * Pull reference to imported modules that were imported from dirName, or + * load required directory if not found + * + * @param {String} dirName The name of the dir to load, relative to the _base path. + */ + getImport (dirName) { + let imported = this._imports[dirName]; + + if (!imported) { + this.loadDir(dirName); + } + + return Object.assign({}, this._imports[dirName]); + } +} + +// automagically loaded directorys on instantiation +ImportsManager.load_dirs = ['src/commands']; + +module.exports = ImportsManager; -- cgit v1.2.1