UNPKG

bal-util

Version:

Common utility functions for Node.js used and maintained by Benjamin Lupton

311 lines (283 loc) 7.59 kB
// Generated by CoffeeScript 2.3.1 // Import var Event, EventEmitter, EventSystem, typeChecker; ({EventEmitter} = require('events')); typeChecker = require('typechecker'); Event = (function() { // ===================================== // Event & EventSystem // Extends the EventEmitterEnhanced with support for: // - blocking events // - start and finish events // Event class Event { // Apply our name on construction constructor({name}) { this.name = name; } }; // The name of the event Event.prototype.name = null; // Is the event currently locked? Event.prototype.locked = false; // Has the event finished running? Event.prototype.finished = false; return Event; }).call(this); EventSystem = (function() { // EventSystem class EventSystem extends EventEmitter { // Fetch the event object for the event event(eventName) { var base; // Prepare this._eventSystemEvents || (this._eventSystemEvents = {}); // Return the fetched event, create it if it doesn't exist already return (base = this._eventSystemEvents)[eventName] || (base[eventName] = new Event(eventName)); } // Lock the event // next(err) lock(eventName, next) { var err, event; // Grab the event event = this.event(eventName); // Grab a lock on the event if (event.locked === false) { // Place the lock event.locked = true; try { // Trigger our event // then fire our callback this.emit(eventName + ':locked'); } catch (error) { err = error; next(err); return this; } finally { next(); } } else { // Wait until the current task has finished this.onceUnlocked(eventName, (err) => { if (err) { return next(err); } // Then try again return this.lock(eventName, next); }); } return this; } // Unlock the event // next(err) unlock(eventName, next) { var err, event; // Grab the event event = this.event(eventName); // Release the lock event.locked = false; try { // Trigger our event // then fire our callback this.emit(eventName + ':unlocked'); } catch (error) { err = error; next(err); return this; } finally { next(); } return this; } // Start our event // 1. Performs a lock // 2. Sets event's finished flag to false // 3. Fires callback // next(err) start(eventName, next) { // Grab a locak this.lock(eventName, (err) => { var event; if (err) { // Error? return next(err); } // Grab the event event = this.event(eventName); // Set as started event.finished = false; try { // Trigger our event // then fire our callback return this.emit(eventName + ':started'); } catch (error) { err = error; next(err); return this; } finally { next(); } }); return this; } // Finish, alias for finished finish(...args) { return this.finished.apply(this, args); } // Finished our event // 1. Sets event's finished flag to true // 2. Unlocks the event // 3. Fires callback // next(err) finished(eventName, next) { var event; // Grab the event event = this.event(eventName); // Set as finished event.finished = true; // Unlock this.unlock(eventName, (err) => { if (err) { // Error? return next(err); } try { // Trigger our event // then fire our callback return this.emit(eventName + ':finished'); } catch (error) { err = error; next(err); return this; } finally { next(); } }); return this; } // Run one time once an event has unlocked // next(err) onceUnlocked(eventName, next) { var event; // Grab the event event = this.event(eventName); // Check lock status if (event.locked) { // Wait until our event has unlocked to fire the callback this.once(eventName + ':unlocked', next); } else { // Fire our callback now next(); } return this; } // Run one time once an event has finished // next(err) onceFinished(eventName, next) { var event; // Grab the event event = this.event(eventName); // Check finish status if (event.finished) { // Fire our callback now next(); } else { // Wait until our event has finished to fire the callback this.once(eventName + ':finished', next); } return this; } // Run every time an event has finished // next(err) whenFinished(eventName, next) { var event; // Grab the event event = this.event(eventName); // Check finish status if (event.finished) { // Fire our callback now next(); } // Everytime our even has finished, fire the callback this.on(eventName + ':finished', next); return this; } // When, alias for on when(...args) { return this.on.apply(this, args); } // Block an event from running // next(err) block(eventNames, next) { var done, err, eventName, i, len, total; // Ensure array if (!typeChecker.isArray(eventNames)) { if (typeChecker.isString(eventNames)) { eventNames = eventNames.split(/[,\s]+/g); } else { err = new Error('Unknown eventNames type'); return next(err); } } total = eventNames.length; done = 0; // Block these events for (i = 0, len = eventNames.length; i < len; i++) { eventName = eventNames[i]; this.lock(eventName, function(err) { // Error? if (err) { done = total; return next(err); } // Increment done++; if (done === total) { return next(); } }); } return this; } // Unblock an event from running // next(err) unblock(eventNames, next) { var done, err, eventName, i, len, total; // Ensure array if (!typeChecker.isArray(eventNames)) { if (typeChecker.isString(eventNames)) { eventNames = eventNames.split(/[,\s]+/g); } else { err = new Error('Unknown eventNames type'); return next(err); } } total = eventNames.length; done = 0; // Block these events for (i = 0, len = eventNames.length; i < len; i++) { eventName = eventNames[i]; this.unlock(eventName, function(err) { // Error? if (err) { done = total; return next(err); } // Increment done++; if (done === total) { return next(); } }); } return this; } }; // Event store // initialised in our event function to prevent javascript reference problems EventSystem.prototype._eventSystemEvents = null; return EventSystem; }).call(this); // ===================================== // Export module.exports = {Event, EventSystem};