From cf3352d0af4a8c93090523ac879ca3df989bc237 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 13 Aug 2020 15:30:44 +1000 Subject: [PATCH] add a timeout function to promiseUtils for attemptConnection --- .../session/SessionClosableOverlay.tsx | 2 +- ts/session/types/OpenGroup.ts | 11 +++++-- ts/session/utils/Promise.ts | 32 +++++++++++++------ ts/test/session/unit/utils/Promise_test.ts | 4 +-- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/ts/components/session/SessionClosableOverlay.tsx b/ts/components/session/SessionClosableOverlay.tsx index 35d6813a3..2e6744b38 100644 --- a/ts/components/session/SessionClosableOverlay.tsx +++ b/ts/components/session/SessionClosableOverlay.tsx @@ -103,7 +103,7 @@ export class SessionClosableOverlay extends React.Component { }); } - // tslint:disable-next-line max-func-body-length */ + // tslint:disable-next-line max-func-body-length cyclomatic-complexity */ public render(): JSX.Element { const { overlayMode, diff --git a/ts/session/types/OpenGroup.ts b/ts/session/types/OpenGroup.ts index 290e1c7f9..4666bdefa 100644 --- a/ts/session/types/OpenGroup.ts +++ b/ts/session/types/OpenGroup.ts @@ -1,4 +1,5 @@ import { ConversationModel } from '../../../js/models/conversations'; +import { PromiseUtils } from '../utils'; interface OpenGroupParams { server: string; @@ -126,8 +127,14 @@ export class OpenGroup { onLoading(); } - conversation = await window.attemptConnection(prefixedServer, channel); - conversationId = conversation?.cid; + conversation = await PromiseUtils.timeout( + window.attemptConnection(prefixedServer, channel), + 5000 + ); + if (!conversation) { + throw new Error(window.i18n('connectToServerFail')); + } + conversationId = (conversation as any)?.cid; } catch (e) { throw new Error(e); } diff --git a/ts/session/utils/Promise.ts b/ts/session/utils/Promise.ts index 9019ff282..237938e77 100644 --- a/ts/session/utils/Promise.ts +++ b/ts/session/utils/Promise.ts @@ -14,13 +14,13 @@ async function toPromise(value: Return): Promise { */ export async function waitForTask( task: (done: SimpleFunction) => Return, - timeout: number = 2000 + timeoutMs: number = 2000 ): Promise { const timeoutPromise = new Promise((_, rej) => { const wait = setTimeout(() => { clearTimeout(wait); rej(new Error('Task timed out.')); - }, timeout); + }, timeoutMs); }); const taskPromise = new Promise(async (res, rej) => { @@ -35,7 +35,7 @@ export async function waitForTask( } export interface PollOptions { - timeout: number; + timeoutMs: number; interval: number; } @@ -51,16 +51,16 @@ export async function poll( options: Partial = {} ): Promise { const defaults: PollOptions = { - timeout: 2000, + timeoutMs: 2000, interval: 100, }; - const { timeout, interval } = { + const { timeoutMs, interval } = { ...defaults, ...options, }; - const endTime = Date.now() + timeout; + const endTime = Date.now() + timeoutMs; let stop = false; const finish = () => { stop = true; @@ -101,7 +101,7 @@ export async function poll( */ export async function waitUntil( check: () => Return, - timeout: number = 2000 + timeoutMs: number = 2000 ) { // This is causing unhandled promise rejection somewhere in MessageQueue tests return poll( @@ -112,8 +112,22 @@ export async function waitUntil( } }, { - timeout, - interval: timeout / 20, + timeoutMs, + interval: timeoutMs / 20, } ); } + +export async function timeout( + promise: Promise, + timeoutMs: number = 2000 +): Promise { + const timeoutPromise = new Promise((_, rej) => { + const wait = setTimeout(() => { + clearTimeout(wait); + rej(new Error('Task timed out.')); + }, timeoutMs); + }); + + return Promise.race([timeoutPromise, promise]); +} diff --git a/ts/test/session/unit/utils/Promise_test.ts b/ts/test/session/unit/utils/Promise_test.ts index b83e1d071..28ec57532 100644 --- a/ts/test/session/unit/utils/Promise_test.ts +++ b/ts/test/session/unit/utils/Promise_test.ts @@ -60,7 +60,7 @@ describe('Promise Utils', () => { const completionSpy = sandbox.spy(); const task = (_done: any) => undefined; - const promise = PromiseUtils.poll(task, { timeout: 1 }); + const promise = PromiseUtils.poll(task, { timeoutMs: 1 }); await expect(promise).to.be.rejectedWith('Periodic check timeout'); expect(pollSpy.callCount).to.equal(1); @@ -82,7 +82,7 @@ describe('Promise Utils', () => { } }; - const promise = PromiseUtils.poll(task, { timeout, interval }); + const promise = PromiseUtils.poll(task, { timeoutMs: timeout, interval }); await expect(promise).to.be.fulfilled; expect(pollSpy.callCount).to.equal(1);