/* This file is part of GNU Taler (C) 2019 GNUnet e.V. TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. TALER is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with TALER; see the file COPYING. If not, see */ /** * An opened promise. * * @see {@link openPromise} */ export interface OpenedPromise { promise: Promise; resolve: (val: T) => void; reject: (err: any) => void; lastError?: any; } /** * Get an unresolved promise together with its extracted resolve / reject * function. * * Recent ECMAScript proposals also call this a promise capability. */ export function openPromise(): OpenedPromise { let resolve: ((x?: any) => void) | null = null; let promiseReject: ((reason?: any) => void) | null = null; const promise = new Promise((res, rej) => { resolve = res; promiseReject = rej; }); if (!(resolve && promiseReject)) { // Never happens, unless JS implementation is broken throw Error("JS implementation is broken"); } const result: OpenedPromise = { resolve, reject: promiseReject, promise }; function saveLastError(reason?: any) { result.lastError = reason; promiseReject!(reason); } result.reject = saveLastError; return result; } export class AsyncCondition { private promCap?: OpenedPromise = undefined; constructor() {} wait(): Promise { if (!this.promCap) { this.promCap = openPromise(); } return this.promCap.promise; } trigger(): void { if (this.promCap) { this.promCap.resolve(); } this.promCap = undefined; } } /** * Flag that can be raised to notify asynchronous waiters. * * You can think of it as a promise that can * be un-resolved. */ export class AsyncFlag { private promCap?: OpenedPromise = undefined; private internalFlagRaised: boolean = false; constructor() {} /** * Wait until the flag is raised. * * Reset if before returning. */ wait(): Promise { if (this.internalFlagRaised) { return Promise.resolve(); } if (!this.promCap) { this.promCap = openPromise(); } return this.promCap.promise; } raise(): void { this.internalFlagRaised = true; if (this.promCap) { this.promCap.resolve(); } } reset(): void { this.internalFlagRaised = false; this.promCap = undefined; } }