UNPKG

@vechain/sdk-network

Version:

This module serves as the standard interface connecting decentralized applications (dApps) and users to the VeChainThor blockchain

163 lines (145 loc) 6.14 kB
import { type SyncPollInputOptions } from './types'; import { InvalidDataType, PollExecution } from '@vechain/sdk-errors'; /** * Sleep for a given amount of time (in milliseconds). * * @param delayInMilliseconds - The amount of time to sleep in milliseconds. */ async function sleep(delayInMilliseconds: number): Promise<void> { await new Promise((resolve) => setTimeout(resolve, delayInMilliseconds)); } /** * Poll until the condition is met. * * @note: Be careful!, this function is synchronous and will block the thread until the condition is met. * Thus mean it can run forever if the condition is never met. * To avoid infinite loop, you can use the `options.maximumIterations` parameter. * * @example It can be used to wait until: * - A balance is updated after a transaction is sent * - A transaction is mined * - A block is mined * ... * * @param pollingFunction - The function to be called. * @param options - Polling options. @see {SyncPollInputOptions} type. If not specified, the default values are used. In particular: `requestIntervalInMilliseconds` is 1000, `maximumIterations` is not specified * and `maximumWaitingTimeInMilliseconds` is not specified. * @returns An object with a `waitUntil` method. It blocks execution until the condition is met. When the condition is met, it returns the result of the poll. * @throws {InvalidDataType, PollExecution} */ function SyncPoll<TReturnType>( pollingFunction: () => Promise<TReturnType> | TReturnType, options?: SyncPollInputOptions ): { waitUntil: ( condition: (data: TReturnType) => boolean ) => Promise<TReturnType>; } { // Positive number for the request interval if ( options?.requestIntervalInMilliseconds !== undefined && (options.requestIntervalInMilliseconds <= 0 || !Number.isInteger(options.requestIntervalInMilliseconds)) ) { throw new InvalidDataType( 'SyncPoll()', 'Polling failed: Invalid input for field "options?.requestIntervalInMilliseconds" it must be a positive number', { requestIntervalInMilliseconds: options.requestIntervalInMilliseconds } ); } // Positive number for maximum iterations if ( options?.maximumIterations !== undefined && (options.maximumIterations <= 0 || !Number.isInteger(options.maximumIterations)) ) { throw new InvalidDataType( 'SyncPoll()', 'Polling failed: Invalid input for field "options?.maximumIterations" it must be a positive number', { maximumIterations: options.maximumIterations } ); } // Positive number for maximum waiting time if ( options?.maximumWaitingTimeInMilliseconds !== undefined && (options.maximumWaitingTimeInMilliseconds <= 0 || !Number.isInteger(options.maximumWaitingTimeInMilliseconds)) ) { throw new InvalidDataType( 'SyncPoll()', 'Polling failed: Invalid input for field "options?.maximumWaitingTimeInMilliseconds" it must be a positive number', { maximumWaitingTimeInMilliseconds: options.maximumWaitingTimeInMilliseconds } ); } // Number of iterations let currentIteration = 0; // Current result let currentResult: TReturnType; // Polling condition let pollingCondition: boolean = false; // Initialize the start time const startTime = Date.now(); return { /** * Poll until the condition is met. * * @param condition - The condition to be met. * @returns The result of the poll after the condition is met. */ waitUntil: async ( condition: (data: TReturnType) => boolean ): Promise<TReturnType> => { try { do { // 1 - Fetch the result of promise currentResult = await pollingFunction(); const isConditionSatisfied = condition(currentResult); if (isConditionSatisfied) { // If the condition is satisfied, return the current result return currentResult; } // 2 - Sleep for the interval (in a synchronous way) await sleep(options?.requestIntervalInMilliseconds ?? 1000); // 3 - Increment the current iteration currentIteration = currentIteration + 1; // 4.1 - Stop forced on iterations const isMaximumIterationsReached = options?.maximumIterations !== undefined ? currentIteration >= options.maximumIterations : false; // 4.2 - Stop forced on maximum waiting time const isTimeLimitReached = options?.maximumWaitingTimeInMilliseconds !== undefined && Date.now() - startTime >= options.maximumWaitingTimeInMilliseconds; // Stop the polling if the condition is met OR the maximum iterations is reached OR the maximum waiting time is reached pollingCondition = !( isConditionSatisfied || isMaximumIterationsReached || isTimeLimitReached ); } while (pollingCondition); return currentResult; } catch (error) { throw new PollExecution( 'SyncPoll.waitUntil()', 'Polling failed: Function execution error encountered during synchronous polling.', { functionName: pollingFunction.name }, error ); } } }; } export { SyncPoll };