You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			119 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			119 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			TypeScript
		
	
| type SimpleFunction<T> = (arg: T) => void;
 | |
| type Return<T> = Promise<T> | T;
 | |
| 
 | |
| async function toPromise<T>(value: Return<T>): Promise<T> {
 | |
|   return value instanceof Promise ? value : Promise.resolve(value);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Create a promise which waits until `done` is called or until `timeout` period is reached.
 | |
|  * If `timeout` is reached then this will throw an Error.
 | |
|  *
 | |
|  * @param task The task to wait for.
 | |
|  * @param timeout The timeout period.
 | |
|  */
 | |
| export async function waitForTask<T>(
 | |
|   task: (done: SimpleFunction<T>) => Return<void>,
 | |
|   timeout: number = 2000
 | |
| ): Promise<T> {
 | |
|   const timeoutPromise = new Promise<T>((_, rej) => {
 | |
|     const wait = setTimeout(() => {
 | |
|       clearTimeout(wait);
 | |
|       rej(new Error('Task timed out.'));
 | |
|     }, timeout);
 | |
|   });
 | |
| 
 | |
|   const taskPromise = new Promise(async (res, rej) => {
 | |
|     try {
 | |
|       await toPromise(task(res));
 | |
|     } catch (e) {
 | |
|       rej(e);
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   return Promise.race([timeoutPromise, taskPromise]) as Promise<T>;
 | |
| }
 | |
| 
 | |
| export interface PollOptions {
 | |
|   timeout: number;
 | |
|   interval: number;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Creates a promise which calls the `task` every `interval` until `done` is called or until `timeout` period is reached.
 | |
|  * If `timeout` is reached then this will throw an Error.
 | |
|  *
 | |
|  * @param task The task which runs every `interval` ms.
 | |
|  * @param options The polling options.
 | |
|  */
 | |
| export async function poll(
 | |
|   task: (done: SimpleFunction<void>) => Return<void>,
 | |
|   options: Partial<PollOptions> = {}
 | |
| ): Promise<void> {
 | |
|   const defaults: PollOptions = {
 | |
|     timeout: 2000,
 | |
|     interval: 1000,
 | |
|   };
 | |
| 
 | |
|   const { timeout, interval } = {
 | |
|     ...defaults,
 | |
|     ...options,
 | |
|   };
 | |
| 
 | |
|   const endTime = Date.now() + timeout;
 | |
|   let stop = false;
 | |
|   const finish = () => {
 | |
|     stop = true;
 | |
|   };
 | |
| 
 | |
|   const _poll = async (resolve: any, reject: any) => {
 | |
|     if (stop) {
 | |
|       resolve();
 | |
|     } else if (Date.now() >= endTime) {
 | |
|       finish();
 | |
|       reject(new Error('Periodic check timeout'));
 | |
|     } else {
 | |
|       try {
 | |
|         await toPromise(task(finish));
 | |
|       } catch (e) {
 | |
|         finish();
 | |
|         reject(e);
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       setTimeout(() => {
 | |
|         void _poll(resolve, reject);
 | |
|       }, interval);
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   return new Promise((resolve, reject) => {
 | |
|     void _poll(resolve, reject);
 | |
|   });
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Creates a promise which waits until `check` returns `true` or rejects if `timeout` preiod is reached.
 | |
|  * If `timeout` is reached then this will throw an Error.
 | |
|  *
 | |
|  * @param check The boolean check.
 | |
|  * @param timeout The time before an error is thrown.
 | |
|  */
 | |
| export async function waitUntil(
 | |
|   check: () => Return<boolean>,
 | |
|   timeout: number = 2000
 | |
| ) {
 | |
|   // This is causing unhandled promise rejection somewhere in MessageQueue tests
 | |
|   return poll(
 | |
|     async done => {
 | |
|       const result = await toPromise(check());
 | |
|       if (result) {
 | |
|         done();
 | |
|       }
 | |
|     },
 | |
|     {
 | |
|       timeout,
 | |
|     }
 | |
|   );
 | |
| }
 |