var path = require('path'), fs = require('fs'), clearRequire = require('./utils/clear-require'), readPackageJson = require('./utils/read-packagejson'); /* NEW */ var Eventual = require('./eventual'); var BundleContext = require('./bundle-context'); var log = require('hlogger').createLogger('bundle-manager'); function solveBundleName(inpath) { var name = path.basename(inpath); if(name == "index.js") { name = path.basename(path.dirname(inpath)); } else { name = path.basename(inpath,".js"); } return name; }; // Common registry class BundleManager { constructor(opts) { // Control events this.config = opts || {}; this.eventual = new Eventual(); //this.events = new XEventEmitter(); // Force for now // Global channel this.stat = { modulesRegistered:0, modulesUnRegistered:0 }; this.registry = {}; //this.registry = []; } generateId() { var id=0; // Slow -- by fetching all ids everytime do { id++; } while(this.get(id) != null); // Slow but one timer return id; } loadDefaultBundles() { var corePath = path.join(__dirname,"../bundles"); fs.readdir(corePath, (err,dir) => { for( var file of dir ) { this.load(path.join(corePath,file)); } }); } getBundleByInstance(instance) { //return this.registry.find((el) => el.instance == instance); for(var k in this.registry) { if(this.registry[k].instance == instance) { return this.registry[k]; } } return null; } getBundleById(id) { //return this.registry.find((el) => el.id == id); for(var k in this.registry) { if(this.registry[k].id == id) { return this.registry[k]; } } return null; } getBundle(name) { //return this.registry.find((el) => el.name == name); return this.registry[name]; } get(obj) { if(isNaN(obj) == false) { return this.getBundleById(obj); } if(typeof(obj) == "string") { return this.getBundle(obj); } if(obj instanceof BundleContext) { return obj; } return this.getBundleByInstance(obj); } load(modPath) { var modName = solveBundleName(modPath); this.register({name: modName,bundle:modPath}); } register(opts) { var {id,name,bundle,autostart} = opts; var instance; var modulePath; var mod = bundle; var version = "unknown"; if(this.getBundle(name) != undefined) { log.error(name + " Already exists"); return; } if(typeof(bundle) == "string") { var modPath= path.resolve(bundle); var modInfo = readPackageJson(bundle); try { mod = require(modPath); } catch(e) { console.error(e); return; } if(mod == undefined) { log.error("Undefined module at: " + bundle); } modulePath = modPath; } if(mod.bundleFactory != undefined) { instance = new mod.bundleFactory() } else { instance = mod; } id = id || this.generateId(); // Simplify this var context = new BundleContext({ id: id, name:name, manager:this, instance: instance, modulePath:modulePath, pkgInfo: modInfo, version:version }); this.stat.modulesRegistered++; this.registry[name] = context; //this.registry.push(context); if(autostart != false) { context.start(); } } unregister(obj) { var context = this.get(obj); if(context == null) { log.error("Context not found for: " + obj); return; } context.stop(); // Unload require if(context.modulePath != undefined) { clearRequire(context.modulePath); } /*this.registry = this.registry.filter((ctx) => { return ctx != context; });*/ delete this.registry[context.name]; this.stat.modulesUnRegistered++; } // Batch call call(name,...args) { var [ctxName, method] = name.split(":") var matchCtx = new RegExp(ctxName); var fretList = []; for(var ctxn in this.registry) { var ctx = this.registry[ctxn]; if(!matchCtx.test(ctx.name)) { continue; } var ret = { name:ctx.name} if(ctx.instance[method] == undefined || typeof(ctx.instance[method]) != "function") { ret.result = 0; ret.error = "method not found"; } else { ret.result = ctx.instance[method](...args); } fretList.push(ret); } return fretList; } with(args,cb) { var mods = args; /*if(typeof(args[args.length-1]) != "function") { throw new Error("Deprecated having callback on argument"); }*/ if(!Array.isArray(args)) { mods = [args]; } // Move this to manager directly var iParam = []; var ret = { // we could create generic out of this, its not a promise success: true, /*do: function(cb) { if(this.success) cb.apply(cb,iParam); return this; },*/ else: function(cb) { if(!this.success)cb(); return this; } } for(var v of mods) { if(v == undefined) throw new Error("What?"); var ctx = this.get(v); if(ctx == null || ctx.info.state != 1) { ret.success = false; break; } // Early bail iParam.push(ctx.instance); } if(ret.success) cb(...iParam); return ret; } } module.exports = BundleManager;