import { Logger } from "./logger"; export class PromiseTimeoutError extends Error { promise?: Promise; constructor(promise?: Promise) { super("Promise timed out"); this.promise = promise; } } export interface PromiseWithState extends Promise { isResolved: boolean; isRejected: boolean; } export function promiseOrTimeout(promise: Promise, timeout?: number): Promise { return Promise.race([timeoutPomise(timeout), promise]); } export function timeoutPomise(timeout?: number): Promise { return new Promise((resolve, reject) => { if (timeout) { setTimeout(() => { reject(new PromiseTimeoutError()); }, timeout); } }); } export function savePromiseState(promise: Promise): PromiseWithState { const p = promise as PromiseWithState; p.isResolved = false; p.isRejected = false; p.then(() => { p.isResolved = true; }).catch(() => { p.isRejected = true; }); return p; } /** * Allows rejection or resolve * Allows past resolves too, but not past rejections */ export function nextFulfilment(promises: PromiseWithState[]): Promise { return Promise.race(promises.filter((p) => !p.isRejected)); } export function oneOf(promises: Promise[]): Promise { return new Promise((resolve, reject) => { let fulfilments = 0; for (const promise of promises) { promise.then((result) => { fulfilments++; if (result || fulfilments === promises.length) { resolve(result); } }).catch((err) => { fulfilments++; if (fulfilments === promises.length) { reject(err); } else { Logger.error(`oneOf ignore error (promise): ${err}`); } }); } }); }