bundle-manager.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. var path = require('path'),
  2. fs = require('fs'),
  3. XEventEmitter = require('./utils/xevents'),
  4. clearRequire = require('./utils/clear-require'),
  5. readPackageJson = require('./utils/read-packagejson');
  6. /* NEW */
  7. var Eventual = require('./eventual');
  8. var BundleContext = require('./bundle-context');
  9. var log = require('hlogger').createLogger('bundle-manager');
  10. function solveBundleName(inpath) {
  11. var name = path.basename(inpath);
  12. if(name == "index.js") {
  13. name = path.basename(path.dirname(inpath));
  14. } else {
  15. name = path.basename(inpath,".js");
  16. }
  17. return name;
  18. };
  19. // Common registry
  20. class BundleManager {
  21. constructor(opts) {
  22. // Control events
  23. this.config = opts || {};
  24. this.eventual = new Eventual();
  25. //this.events = new XEventEmitter(); // Force for now
  26. // Global channel
  27. this.globalEvents = new XEventEmitter();
  28. this.stat = {
  29. modulesRegistered:0,
  30. modulesUnRegistered:0
  31. };
  32. this.registry = {};
  33. //this.registry = [];
  34. }
  35. generateId() {
  36. var id=0;
  37. // Slow -- by fetching all ids everytime
  38. do { id++; } while(this.get(id) != null); // Slow but one timer
  39. return id;
  40. }
  41. loadDefaultBundles() {
  42. var corePath = path.join(__dirname,"../bundles");
  43. fs.readdir(corePath, (err,dir) => {
  44. for( var file of dir ) {
  45. this.load(path.join(corePath,file));
  46. }
  47. });
  48. }
  49. getBundleByInstance(instance) {
  50. //return this.registry.find((el) => el.instance == instance);
  51. for(var k in this.registry) {
  52. if(this.registry[k].instance == instance) {
  53. return this.registry[k];
  54. }
  55. }
  56. return null;
  57. }
  58. getBundleById(id) {
  59. //return this.registry.find((el) => el.id == id);
  60. for(var k in this.registry) {
  61. if(this.registry[k].id == id) {
  62. return this.registry[k];
  63. }
  64. }
  65. return null;
  66. }
  67. getBundle(name) {
  68. //return this.registry.find((el) => el.name == name);
  69. return this.registry[name];
  70. }
  71. get(obj) {
  72. if(isNaN(obj) == false) {
  73. return this.getBundleById(obj);
  74. }
  75. if(typeof(obj) == "string") {
  76. return this.getBundle(obj);
  77. }
  78. if(obj instanceof BundleContext) {
  79. return obj;
  80. }
  81. return this.getBundleByInstance(obj);
  82. }
  83. load(modPath) {
  84. var modName = solveBundleName(modPath);
  85. this.register({name: modName,bundle:modPath});
  86. }
  87. register(opts) {
  88. var {id,name,bundle,autostart} = opts;
  89. var instance;
  90. var modulePath;
  91. var mod = bundle;
  92. var version = "unknown";
  93. if(this.getBundle(name) != undefined) {
  94. log.error(name + " Already exists");
  95. return;
  96. }
  97. if(typeof(bundle) == "string") {
  98. var modPath= path.resolve(bundle);
  99. var modInfo = readPackageJson(bundle);
  100. try {
  101. mod = require(modPath);
  102. } catch(e) {
  103. console.error(e);
  104. return;
  105. }
  106. if(mod == undefined) {
  107. log.error("Undefined module at: " + bundle);
  108. }
  109. modulePath = modPath;
  110. }
  111. if(mod.bundleFactory != undefined) {
  112. instance = new mod.bundleFactory()
  113. } else {
  114. instance = mod;
  115. }
  116. id = id || this.generateId();
  117. // Simplify this
  118. var context = new BundleContext({
  119. id: id,
  120. name:name,
  121. manager:this,
  122. instance: instance,
  123. modulePath:modulePath,
  124. pkgInfo: modInfo,
  125. version:version
  126. });
  127. this.stat.modulesRegistered++;
  128. this.registry[name] = context;
  129. //this.registry.push(context);
  130. if(autostart != false) {
  131. context.start();
  132. }
  133. }
  134. unregister(obj) {
  135. var context = this.get(obj);
  136. if(context == null) {
  137. log.error("Context not found for: " + obj);
  138. return;
  139. }
  140. context.stop();
  141. // Unload require
  142. if(context.modulePath != undefined) {
  143. clearRequire(context.modulePath);
  144. }
  145. /*this.registry = this.registry.filter((ctx) => {
  146. return ctx != context;
  147. });*/
  148. delete this.registry[context.name];
  149. this.stat.modulesUnRegistered++;
  150. }
  151. // Batch call
  152. call(name,args) {
  153. var [ctxName, method] = name.split(":")
  154. var matchCtx = new RegExp(ctxName);
  155. var fretList = [];
  156. for(var ctxn in this.registry) {
  157. var ctx = this.registry[ctxn];
  158. if(!matchCtx.test(ctx.name)) {
  159. continue;
  160. }
  161. var ret = { name:ctx.name}
  162. if(ctx.instance[method] == undefined || typeof(ctx.instance[method]) != "function") {
  163. ret.result = 0;
  164. ret.error = "method not found";
  165. } else {
  166. ret.result = ctx.instance[method](args);
  167. }
  168. fretList.push(ret);
  169. }
  170. return fretList;
  171. }
  172. with(args,cb) {
  173. var mods = args;
  174. /*if(typeof(args[args.length-1]) != "function") {
  175. throw new Error("Deprecated having callback on argument");
  176. }*/
  177. if(!Array.isArray(args)) {
  178. mods = [args];
  179. }
  180. // Move this to manager directly
  181. var iParam = [];
  182. var ret = { // we could create generic out of this, its not a promise
  183. success: true,
  184. /*do: function(cb) {
  185. if(this.success) cb.apply(cb,iParam);
  186. return this;
  187. },*/
  188. else: function(cb) {
  189. if(!this.success)cb();
  190. return this;
  191. }
  192. }
  193. for(var v of mods) {
  194. if(v == undefined) throw new Error("What?");
  195. var ctx = this.get(v);
  196. if(ctx == null || ctx.info.state != 1) {
  197. ret.success = false;
  198. break;
  199. } // Early bail
  200. iParam.push(ctx.instance);
  201. }
  202. if(ret.success) cb(...iParam);
  203. return ret;
  204. }
  205. }
  206. module.exports = BundleManager;