xevents.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. var log = require('hlogger').createLogger('xevents');
  2. class XPrefix {
  3. constructor(ctx,event,prefix) {
  4. this.ctx = ctx;
  5. this.event = event;
  6. this.prefix = prefix || "";
  7. }
  8. on(name,cb) {
  9. this.event.on(this.ctx,this.prefix + ":" + name,cb);
  10. return this;
  11. }
  12. }
  13. class XEvent {
  14. constructor(donecb,args) {
  15. this.count = 0;
  16. this.dowait = 0;
  17. this.done= donecb; // Callback
  18. this.errors = [];
  19. this.params = args;
  20. }
  21. wait() {
  22. this.dowait = 1;
  23. }
  24. }
  25. class XEventListener {
  26. constructor(ctx,name,cb,order) {
  27. this.ctx = ctx;
  28. this.name = name;
  29. this.callback = cb;
  30. this.order = order || 0; // Late call
  31. }
  32. }
  33. // Smarter event system?
  34. class XEventEmitter {
  35. constructor() {
  36. // Prepare this in a single context
  37. //this.listeners = new Map();
  38. this.listeners = [];
  39. this.auto = {};
  40. this.stat = {
  41. emitted:0,
  42. tried:0,
  43. called:0
  44. }
  45. }
  46. addListener(...args) {
  47. var ctx = this,evtName,cb,order;
  48. if(typeof(args[0]) == "string") {
  49. [evtName,cb,order] = args;
  50. } else {
  51. [ctx,evtName,cb,order] = args;
  52. }
  53. // Manipulate the evtName as in:
  54. //
  55. /*var re = /[^\\]{(.*?)}/;
  56. var paramMap = [];
  57. do {
  58. var res = evtName.match(re)
  59. if(res != null) {
  60. paramMap.push(res[1]);
  61. // The match + first char of the match
  62. evtName = evtName.replace(re,res[0][0]+"(.*)");
  63. }
  64. }while(res != null);
  65. console.log("Resulting evtName: " + evtName);*/
  66. var listener = new XEventListener(ctx,evtName,cb,order);
  67. //listener.paramMap = paramMap;
  68. this.listeners.push(listener);
  69. //this.listeners.push(entry);
  70. // Process the autos
  71. var re = new RegExp(evtName);
  72. Object.keys(this.auto).map((v) => {
  73. var match = v.match(re);
  74. if(v.match(re)) {
  75. this.process([{match:match,listener:listener}],this.auto[v]);
  76. }
  77. });
  78. /* try {
  79. cb(this.auto[v], new XEvent());
  80. } catch(e) {
  81. console.log(e);
  82. }
  83. }
  84. });*/
  85. }
  86. // Remove listeners by ctx
  87. removeListener(ctx,name) {
  88. this.listeners = this.listeners.filter((v) => {
  89. if(v == ctx || v.ctx == ctx) {
  90. } else {
  91. return v;
  92. }
  93. });
  94. }
  95. // 1 arg only
  96. toggleOn(name,arg) {
  97. this.auto[name]= arg;
  98. this.emit(name,arg);
  99. }
  100. toggleOff(name) {
  101. delete this.auto[name];
  102. }
  103. process(tocall,args,cb) {
  104. var self=this;
  105. var evt = new XEvent(next,args);
  106. this.stat.emitted++;
  107. // Sort
  108. tocall = tocall.sort((a,b) => {
  109. return (a.listener.order - b.listener.order)
  110. });
  111. // Get iter and setup evt
  112. var iter = tocall[Symbol.iterator]();
  113. function next() {
  114. process.nextTick(() => chain(iter));
  115. }
  116. // Internal thing
  117. function chain(iter) {
  118. // Stack overflow risk? maybe put this in process.tick();
  119. var v = iter.next();
  120. if(v.done) {
  121. if(cb != undefined) cb(evt);
  122. return;
  123. }
  124. // Create evt here with some global event chaining iteraction
  125. try {
  126. var entry = v.value;
  127. evt.match = entry.match;
  128. evt.args = args;
  129. self.stat.called++;
  130. entry.listener.callback(args,evt);
  131. evt.count++;
  132. }catch(e) {
  133. console.log(e);
  134. evt.errors.push(e);
  135. // Should we stop??
  136. }
  137. if(!evt.dowait) next();
  138. evt.dowait=0; // reset wait?
  139. }
  140. next();
  141. }
  142. search(name,ctx) {
  143. var ret = [];
  144. this.listeners.forEach((v) => {
  145. var re = new RegExp( "^" + v.name+ "$" );
  146. var matchres = name.match(re);
  147. if(matchres && (ctx == undefined || ctx == v.ctx) ) {
  148. ret.push({
  149. match: matchres,
  150. listener:v
  151. });
  152. }
  153. });
  154. return ret;
  155. }
  156. emit(name,args) {
  157. this.stat.tried++;
  158. var tocall = this.search(name);
  159. // Mem leak???
  160. var ret = {
  161. param: null,
  162. callback: null,
  163. // Setup callback
  164. trigger: function(args,evt) {
  165. this.param = [args,evt];
  166. this.dotrigger = 1;
  167. if(this.callback) {this.callback(args,evt);}
  168. },
  169. done: function(cb) {
  170. if(this.dotrigger) {
  171. cb(...param);
  172. }
  173. this.callback = cb;
  174. }
  175. }
  176. // Test
  177. this.process(tocall,args,(evt) => { ret.trigger(args,evt) });
  178. return ret ;
  179. }
  180. // Why?
  181. emitTo(ctx,name,args) {
  182. var tocall = this.search(name,ctx)
  183. this.process(tocall,arg,cb);
  184. }
  185. // Alias
  186. on(ctx,match,cb) {
  187. this.addListener(ctx,match,cb);
  188. return this;
  189. }
  190. after(ctx,match,cb) {
  191. this.addListener(ctx,match,cb,1000);
  192. return this;
  193. }
  194. prefix(ctx,prefix) {
  195. return new XPrefix(ctx,this,prefix);
  196. }
  197. /*when(ctx,match,cb) {
  198. this.addListener(ctx,match,cb);
  199. }*/
  200. }
  201. module.exports=XEventEmitter;