bundle-manager.js 5.0 KB

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