diffusion
Version:
Diffusion JavaScript client
292 lines (291 loc) • 9.56 kB
JavaScript
;
/**
* @module events
*/
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Emitter = void 0;
var errors_1 = require("./../../errors/errors");
var stream_1 = require("./../events/stream");
var functions = require("./../util/function");
var EmitterEventQueue = /** @class */ (function () {
function EmitterEventQueue() {
this.pendingEvents = [];
this.events = [];
this.busy = false;
}
/**
* Add an emitter event to the queue
*/
EmitterEventQueue.prototype.addEmitterEvent = function (event) {
var _this = this;
this.pendingEvents.push(event);
if (!this.busy) {
this.busy = true;
process.nextTick(function () {
_this.drainEmitterQueue();
});
}
};
/**
* Process all pending events
*/
EmitterEventQueue.prototype.drainEmitterQueue = function () {
var e_1, _a;
var _this = this;
this.events = this.pendingEvents;
this.pendingEvents = [];
try {
for (var _b = __values(this.events), _c = _b.next(); !_c.done; _c = _b.next()) {
var event_1 = _c.value;
try {
event_1();
}
catch (err) { /* no-op */ }
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
if (this.pendingEvents.length > 0) {
process.nextTick(function () {
_this.drainEmitterQueue();
});
}
else {
this.busy = false;
}
};
return EmitterEventQueue;
}());
var emitterEventQueue = new EmitterEventQueue();
/**
* An internal class to construct implementations of {@link events.Stream} with
* a privately scoped emit function.
*
* This allows safe construction of event-based interfaces without exposing the
* means of emitting events.
*/
var Emitter = /** @class */ (function () {
/**
* Create an Emitter
*
* If a {@link Stream} is provided in the options, the Emitter will use it as
* the stream to emit events to. In this case, the `listeners` must also be
* supplied.
*
* If no {@link Stream} is provided, one will be created with the optional
* `allowedEvents` option.
*
* If the `event` option is specified, listeners will be registered by calling
* {@link Stream.on} passing the `event` option and the `callback` option as
* parameters.
*
* @param options options for creating the Emitter
*/
function Emitter(options) {
var _this = this;
/**
* The listeners object mapping event names to arrays of callback functions
*/
this.listeners = {};
/**
* A flag indicating whether the Emitter is closed
*/
this.closed = false;
/**
* A single listener that will be called whenever an event is emitted. The
* event name will be passed as the first argument.
*/
this.listener = function () { };
if (options === undefined || options.stream === undefined) {
var helper = {
getListeners: function () {
return _this.listeners;
},
getErrorCallback: function () {
return _this.error.bind(_this);
},
getCloseCallback: function () {
return _this.close.bind(_this);
}
};
this.stream = new stream_1.StreamImpl(helper);
}
else {
this.stream = options.stream;
if (options.listeners === undefined) {
throw new errors_1.InternalError('Listeners must be defined when supplying a stream');
}
this.listeners = options.listeners;
}
if (options !== undefined && options.event !== undefined) {
this.stream.on(options.event, options.callback);
}
}
/**
* Create an emitter factory that can create an Emitter.
*
* @param allowedEvents a list of allowed event names
* @return a factory that creates an Emitter
*/
Emitter.create = function () {
var listeners = {};
var errorCallback = function () { };
var closeCallback = function () { };
return {
getListeners: function () {
return listeners;
},
getErrorCallback: function () {
return function (err) {
errorCallback(err);
};
},
getCloseCallback: function () {
return function (reason) {
closeCallback(reason);
};
},
emitter: function (stream) {
var emitter = new Emitter({
stream: stream,
listeners: listeners
});
errorCallback = emitter.error.bind(emitter);
closeCallback = emitter.close.bind(emitter);
return emitter;
}
};
};
/**
* Emit an event without checking if the emitter is closed.
*
* @see {@link Emitter.emit}
*
* @param event the event name
* @param args arguments to pass to the listeners
*/
Emitter.prototype.emitUnsafe = function (event, args) {
var _this = this;
var dispatch = function (listener) {
functions.callWithArguments(listener, args || []);
};
emitterEventQueue.addEmitterEvent(function () {
// eslint-disable-next-line no-prototype-builtins
if (_this.listeners.hasOwnProperty(event)) {
_this.listeners[event].forEach(dispatch);
}
});
this.listener(event, args);
};
/**
* Emit an event.
*
* When an event is emitted, all listeners registered with the `Stream` for
* this event will be called.
*
* If the emitter is closed, or no `event` is specified, nothing will be emitted.
*
* Any additional arguments will be passed to the listeners.
*
* @param event the event name
* @param args arguments to pass to the listeners
*/
Emitter.prototype.emit = function (event) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
if (this.closed || !event) {
return;
}
this.emitUnsafe(event, args);
};
/**
* Process an event immediately.
*
* <p>Experimental.
*/
Emitter.prototype.immediate = function (event) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
if (this.closed || !event) {
return;
}
var dispatch = function (listener) {
try {
functions.callWithArguments(listener, args || []);
}
catch (err) { /* no-op */ }
};
// eslint-disable-next-line no-prototype-builtins
if (this.listeners.hasOwnProperty(event)) {
this.listeners[event].forEach(dispatch);
}
};
/**
* Signal a error and close the emitter. This will emit an `error` event and
* subsequently a `close` event. No further events will be emitted.
*
* @param reason the error causing the emitter to close
*/
Emitter.prototype.error = function (reason) {
if (this.closed) {
return;
}
this.emitUnsafe('error', [reason]);
this.close((reason) ? reason.message : undefined);
};
/**
* Close the emitter. This will emit a `close` event.
* No further events will be emitted.
*
* @param reason the reason for closing the emitter. This can be of any type.
* The type of the close reason should be documented in the
* concrete implementation of the {@link Stream} that the
* emitter is linked to.
*/
Emitter.prototype.close = function (reason) {
if (this.closed) {
return;
}
this.closed = true;
this.emitUnsafe('close', [reason]);
};
/**
* Add a listener to all events
*
* @param fn a callback function that will be called whenever an event is
* emitted. The event name will be passed as the first argument.
*/
Emitter.prototype.listen = function (fn) {
this.listener = fn;
};
/**
* Get the stream that is used to register the callbacks
*
* @return the internal stream object
*/
Emitter.prototype.get = function () {
return this.stream;
};
return Emitter;
}());
exports.Emitter = Emitter;