@freemework/common
Version:
Common library of the Freemework Project.
128 lines • 4.84 kB
JavaScript
import { FCancellationException } from "../cancellation/index.js";
import { FException, FExceptionAggregate, FExceptionInvalidOperation } from "../exception/index.js";
export class FChannelSubscriberMixin {
__callbacks;
__broken;
static applyMixin(targetClass) {
Object.getOwnPropertyNames(FChannelSubscriberMixin.prototype).forEach(name => {
const propertyDescr = Object.getOwnPropertyDescriptor(FChannelSubscriberMixin.prototype, name);
if (name === "constructor") {
// Skip constructor
return;
}
if (name === "onAddFirstHandler" || name === "onRemoveLastHandler") {
// Add NOP methods into mixed only if it not implements its
if (propertyDescr !== undefined) {
const existingPropertyDescr = Object.getOwnPropertyDescriptor(targetClass.prototype, name);
if (existingPropertyDescr === undefined) {
Object.defineProperty(targetClass.prototype, name, propertyDescr);
}
}
return;
}
if (propertyDescr !== undefined) {
Object.defineProperty(targetClass.prototype, name, propertyDescr);
}
});
}
addHandler(cb) {
this.verifyBrokenChannel();
if (this.__callbacks === undefined) {
this.__callbacks = [];
}
this.__callbacks.push(cb);
if (this.__callbacks.length === 1) {
this.onAddFirstHandler();
}
}
removeHandler(cb) {
if (this.__callbacks === undefined) {
return;
}
const index = this.__callbacks.indexOf(cb);
if (index !== -1) {
this.__callbacks.splice(index, 1);
if (this.__callbacks.length === 0) {
this.onRemoveLastHandler();
}
}
}
get isBroken() { return this.__broken !== undefined && this.__broken; }
verifyBrokenChannel() {
if (this.isBroken) {
throw new FExceptionInvalidOperation("Wrong operation on broken channel");
}
}
notify(executionContext, event) {
if (this.__callbacks === undefined || this.__callbacks.length === 0) {
return;
}
const callbacks = this.__callbacks.slice();
if (event instanceof Error) {
this.__broken = true;
this.__callbacks.splice(0, this.__callbacks.length);
}
if (callbacks.length === 1) {
const callback = callbacks[0];
return callback(executionContext, event);
}
const promises = [];
const errors = [];
for (const callback of callbacks) {
try {
const result = callback(executionContext, event);
if (result instanceof Promise) {
promises.push(result);
}
}
catch (e) {
const ex = FException.wrapIfNeeded(e);
errors.push(ex);
}
}
if (promises.length === 1 && errors.length === 0) {
return promises[0];
}
else if (promises.length > 0) {
return Promise
.all(promises.map(function (p) {
return p.catch(function (e) {
const ex = FException.wrapIfNeeded(e);
errors.push(ex);
});
}))
.then(function () {
if (errors.length > 0) {
for (const error of errors) {
if (!(error instanceof FCancellationException)) {
throw new FExceptionAggregate(errors);
}
}
// So, all errors are FCancellationException instances, throw first
throw errors[0];
}
});
}
else {
if (errors.length > 0) {
for (const error of errors) {
if (!(error instanceof FCancellationException)) {
throw new FExceptionAggregate(errors);
}
}
// So, all errors are FCancellationException instances, throw first
throw errors[0];
}
}
}
get hasSubscribers() { return this.__callbacks !== undefined && this.__callbacks.length > 0; }
onAddFirstHandler() { }
onRemoveLastHandler() { }
constructor() {
// Never called, due mixin
// Private constructor has two kinds of responsibility
// 1) Restrict to extends the mixin
// 2) Restrict to make instances of the mixin
}
}
//# sourceMappingURL=FChannelSubscriberMixin.js.map