mirror of
https://github.com/pezkuwichain/pezkuwi-api.git
synced 2026-05-06 00:58:04 +00:00
Rebrand: polkadot → pezkuwi, substrate → bizinikiwi, kusama → dicle
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
// Copyright 2017-2025 @pezkuwi/api authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Callback } from '@pezkuwi/types/types';
|
||||
import type { UnsubscribePromise } from '../types/index.js';
|
||||
|
||||
import { isFunction, noop } from '@pezkuwi/util';
|
||||
|
||||
export type CombinatorCallback <T extends unknown[]> = Callback<T>;
|
||||
|
||||
export type CombinatorFunction = (cb: Callback<any>) => UnsubscribePromise;
|
||||
|
||||
export class Combinator<T extends unknown[] = unknown[]> {
|
||||
#allHasFired = false;
|
||||
#callback: CombinatorCallback<T>;
|
||||
#fired: boolean[] = [];
|
||||
#fns: CombinatorFunction[] = [];
|
||||
#isActive = true;
|
||||
#results: unknown[] = [];
|
||||
#subscriptions: UnsubscribePromise[] = [];
|
||||
|
||||
constructor (fns: (CombinatorFunction | [CombinatorFunction, ...unknown[]])[], callback: CombinatorCallback<T>) {
|
||||
this.#callback = callback;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises, @typescript-eslint/require-await
|
||||
this.#subscriptions = fns.map(async (input, index): UnsubscribePromise => {
|
||||
const [fn, ...args] = Array.isArray(input)
|
||||
? input
|
||||
: [input];
|
||||
|
||||
this.#fired.push(false);
|
||||
this.#fns.push(fn);
|
||||
|
||||
// Not quite 100% how to have a variable number at the front here
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return,@typescript-eslint/ban-types
|
||||
return (fn as Function)(...args, this._createCallback(index));
|
||||
});
|
||||
}
|
||||
|
||||
protected _allHasFired (): boolean {
|
||||
this.#allHasFired ||= this.#fired.filter((hasFired): boolean => !hasFired).length === 0;
|
||||
|
||||
return this.#allHasFired;
|
||||
}
|
||||
|
||||
protected _createCallback (index: number): (value: any) => void {
|
||||
return (value: unknown): void => {
|
||||
this.#fired[index] = true;
|
||||
this.#results[index] = value;
|
||||
|
||||
this._triggerUpdate();
|
||||
};
|
||||
}
|
||||
|
||||
protected _triggerUpdate (): void {
|
||||
if (!this.#isActive || !isFunction(this.#callback) || !this._allHasFired()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Promise
|
||||
.resolve(this.#callback(this.#results as T))
|
||||
.catch(noop);
|
||||
} catch {
|
||||
// swallow, we don't want the handler to trip us up
|
||||
}
|
||||
}
|
||||
|
||||
public unsubscribe (): void {
|
||||
if (!this.#isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#isActive = false;
|
||||
|
||||
Promise
|
||||
.all(this.#subscriptions.map(async (subscription): Promise<void> => {
|
||||
try {
|
||||
const unsubscribe = await subscription;
|
||||
|
||||
if (isFunction(unsubscribe)) {
|
||||
unsubscribe();
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
})).catch(() => {
|
||||
// ignore, already ignored above, should never throw
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user