import * as ProgressBar from 'progress' ; import { logger } from './logger' ; export function sleep ( ms ) { return new Promise ( resolve => { setTimeout ( resolve , ms ) ; } ) ; } interface PollOptions < T > { makeRequest : ( ) => Promise < T > ; isDone : ( data : T ) => boolean ; shouldIgnoreError ? : ( error : Error ) => boolean ; getProgress ? : ( data : T ) => number ; } let progressBar = null ; function updateProgressBar ( ratio ) { if ( progressBar === null || progressBar . complete ) { return ; } progressBar . update ( ratio ) ; } export function terminateProgressBar ( ) { if ( progressBar !== null && ! progressBar . complete ) { progressBar . terminate ( ) ; } progressBar = null ; } /**
 * When running certain tasks we need to continuously call the API to retrieve
 * new information and to see if the task is completed. To prevent making
 * thousands of requests when waiting for long-running tasks to complete we
 * poll at varying intervals, starting from 250ms up to 10,000ms. This reduces
 * the amount of requests being made while still delivering results swiftly if
 * the task is done quickly.
 */ export async function poll < T > ( { makeRequest , isDone , shouldIgnoreError , getProgress } ) { const intervals = [ [ 250 , 4 ] , [ 1000 , 9 ] , [ 2000 , 10 ] , [ 5000 , 54 ] , [ 10000 , 1e9 ] , ] ; let pollCounter = 0 ; let currentIntervalIndex = 0 ; let data = null ; progressBar = getProgress !== undefined ? logger . progress ( ) : null ; while ( true ) { let dataUpdated = true ; try { data = await makeRequest ( ) ; } catch ( err ) { if ( shouldIgnoreError === undefined || ! shouldIgnoreError ( err ) ) { throw err ; } dataUpdated = false ; } if ( dataUpdated && getProgress !== undefined ) { updateProgressBar ( getProgress ( data ) ) ; } if ( dataUpdated && isDone ( data ) ) { terminateProgressBar ( ) ; return data ; } await sleep ( intervals [ currentIntervalIndex ] [ 0 ] ) ; pollCounter ++ ; if ( pollCounter === intervals [ currentIntervalIndex ] [ 1 ] ) { currentIntervalIndex ++ ; pollCounter = 0 ; } } }