@freemework/common
Version:
Common library of the Freemework Project.
99 lines (87 loc) • 2.96 kB
text/typescript
import { FCancellationException } from "../cancellation/index.js";
import { FException, FExceptionAggregate } from "../exception/index.js";
import { FExecutionContext } from "../execution_context/index.js";
import { FChannelEvent } from "./FChannelEvent.js";
export class FChannelEventBase<
TData = Uint8Array,
TEvent extends FChannelEvent.Event<TData> = FChannelEvent.Event<TData>> implements FChannelEvent<TData, TEvent> {
private _callbacks?: Array<FChannelEvent.Callback<TData, TEvent>>;
public addHandler(cb: FChannelEvent.Callback<TData, TEvent>): void {
if (this._callbacks === undefined) { this._callbacks = []; }
this._callbacks.push(cb);
if (this._callbacks.length === 1) {
this.onAddFirstHandler();
}
}
public removeHandler(cb: FChannelEvent.Callback<TData, TEvent>): void {
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();
}
}
}
protected constructor() {
this._callbacks = [];
}
protected notify(executionContext: FExecutionContext, event: TEvent): Promise<void> {
if (this._callbacks === undefined || this._callbacks.length === 0) {
return Promise.resolve();
}
const callbacks = this._callbacks.slice();
if (callbacks.length === 1) {
const callback = callbacks[0]!;
return callback(executionContext, event);
}
const promises: Array<Promise<void>> = [];
const errors: Array<FException> = [];
for (const callback of callbacks) {
try {
const result: Promise<void> = callback(executionContext, event);
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: Promise<void>) {
return p.catch(function (e: unknown) {
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];
} else {
return Promise.resolve();
}
}
}
protected get hasSubscribers(): boolean { return this._callbacks !== undefined && this._callbacks.length > 0; }
protected onAddFirstHandler(): void { /* NOP */ }
protected onRemoveLastHandler(): void { /* NOP */ }
}