var log = require('hlogger').createLogger('xevents'); class XPrefix { constructor(ctx,event,prefix) { this.ctx = ctx; this.event = event; this.prefix = prefix || ""; } on(name,cb) { this.event.on(this.ctx,this.prefix + ":" + name, cb); return this; } } class XEvent { constructor(donecb,args) { this.count = 0; this.dowait = 0; this.done= donecb; // Callback this.errors = []; this.params = args; } wait() { this.dowait = 1; } } class XEventListener { constructor(ctx,name,cb,order) { this.ctx = ctx; this.name = name; this.callback = cb; this.order = order || 0; // Late call } } // Smarter event system? class XEventEmitter { constructor() { // Prepare this in a single context //this.listeners = new Map(); this.listeners = []; this.auto = {}; this.stat = { emitted:0, tried:0, called:0 } } addListener(...args) { var ctx = this,evtName,cb,order; if(typeof(args[0]) == "string") { [evtName,cb,order] = args; } else { [ctx,evtName,cb,order] = args; } var listener = new XEventListener(ctx,evtName,cb,order); this.listeners.push(listener); //this.listeners.push(entry); // Process the autos var re = new RegExp(evtName); Object.keys(this.auto).map((v) => { var match = v.match(re); if(v.match(re)) { var tocall = [{match:match,listener:listener}]; this.process(tocall,this.auto[v]); // No callback } }); /* try { cb(this.auto[v], new XEvent()); } catch(e) { console.log(e); } } });*/ } // Remove listeners by ctx removeListener(ctx,name) { this.listeners = this.listeners.filter((v) => { if(v == ctx || v.ctx == ctx) { } else { return v; } }); } // 1 arg only toggleOn(name,...args) { // Should be contextual if we remove context toggle will remain this.auto[name] = args; // should store array this.emit(name,...args); } toggleOff(name) { delete this.auto[name]; } process(tocall,nargs,cb) { var self=this; var args = nargs || []; // or empty // Common for all for now var evt = new XEvent(next,args); this.stat.emitted++; // Sort tocall = tocall.sort((a,b) => { return (a.listener.order - b.listener.order) }); // Get iter and setup evt var iter = tocall[Symbol.iterator](); function next() { process.nextTick(() => chain(iter)); } // Internal thing function chain(iter) { // Stack overflow risk? maybe put this in process.tick(); var v = iter.next(); if(v.done) { if(cb != undefined) cb(evt); // Done callback with evt only return; } // Create evt here with some global event chaining iteraction try { var entry = v.value; evt.match = entry.match; evt.args = args; self.stat.called++; entry.listener.callback(...args,evt); evt.count++; }catch(e) { console.log(e); evt.errors.push(e); // Should we stop?? } if(!evt.dowait) next(); evt.dowait=0; // reset wait? } next(); } search(name,ctx) { var ret = []; this.listeners.forEach((v) => { var re = new RegExp( "^" + v.name+ "$" ); //var re = v.name; var matchres = name.match(re); if(matchres && (ctx == undefined || ctx == v.ctx) ) { ret.push({ match: matchres, listener:v }); } }); return ret; } // Multiple argument // Should work like emit("event",1,2,3,4,5); emit(name,...args) { this.stat.tried++; var tocall = this.search(name); var evt,callback,dotrigger = 0; function trigger(ievt) { evt = ievt; // Will call if(callback)callback(evt); } // Mem leak??? var ret = { done: function(cb) { if(evt) { cb(evt); } callback = cb; } } // Test this.process(tocall,args, trigger ); return ret ; } // Why? /*emitTo(ctx,name,args) { var tocall = this.search(name,ctx) this.process(tocall,arg,cb); }*/ // Alias on(ctx,match,cb) { this.addListener(ctx,match,cb); return this; } after(ctx,match,cb) { this.addListener(ctx,match,cb,1000); return this; } prefix(ctx,prefix) { return new XPrefix(ctx,this,prefix); } /*when(ctx,match,cb) { this.addListener(ctx,match,cb); }*/ } module.exports=XEventEmitter;