bal-util
Version:
Common utility functions for Node.js used and maintained by Benjamin Lupton
311 lines (283 loc) • 7.59 kB
JavaScript
// 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};