From 4024cd1585b221cb7e0cc2a0f2259826acd8f601 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Thu, 19 Aug 2021 03:16:39 +0300 Subject: [PATCH] Workaround for a disconnected worker on iOS --- src/api/gramjs/worker/provider.ts | 31 ++++++++++++++++++++++++++++++- src/api/gramjs/worker/types.ts | 3 +++ src/api/gramjs/worker/worker.ts | 8 ++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/api/gramjs/worker/provider.ts b/src/api/gramjs/worker/provider.ts index 8839f7fe5..714a48cf0 100644 --- a/src/api/gramjs/worker/provider.ts +++ b/src/api/gramjs/worker/provider.ts @@ -4,6 +4,7 @@ import { WorkerMessageEvent, ThenArg, OriginRequest } from './types'; import { DEBUG } from '../../../config'; import generateIdFor from '../../../util/generateIdFor'; +import { pause } from '../../../util/schedulers'; type RequestStates = { messageId: string; @@ -12,6 +13,9 @@ type RequestStates = { callback?: AnyToVoidFunction; }; +const HEALTH_CHECK_TIMEOUT = 1000; // 1 sec +const HEALTH_CHECK_MIN_DELAY = 5 * 1000; // 5 sec + let worker: Worker; const requestStates = new Map(); const requestStatesByCallback = new Map(); @@ -27,6 +31,10 @@ export function initApi(onUpdate: OnApiUpdate, initialArgs: ApiInitialArgs) { worker = new Worker(new URL('./worker.ts', import.meta.url)); subscribeToWorker(onUpdate); + + if (initialArgs.platform === 'iOS') { + setupIosHealthCheck(); + } } return makeRequest({ @@ -104,7 +112,7 @@ function makeRequest(message: OriginRequest) { Object.assign(requestState, { resolve, reject }); }); - if (typeof payload.args[1] === 'function') { + if (('args' in payload) && typeof payload.args[1] === 'function') { const callback = payload.args.pop() as AnyToVoidFunction; requestState.callback = callback; requestStatesByCallback.set(callback, requestState); @@ -125,3 +133,24 @@ function makeRequest(message: OriginRequest) { return promise; } + +const startedAt = Date.now(); + +// Workaround for iOS sometimes stops interacting with worker +function setupIosHealthCheck() { + window.addEventListener('focus', async () => { + try { + await Promise.race([ + makeRequest({ type: 'ping' }), + pause(HEALTH_CHECK_TIMEOUT).then(() => Promise.reject(new Error('HEALTH_CHECK_TIMEOUT'))), + ]); + } catch (err) { + // eslint-disable-next-line no-console + console.error(err); + + if (Date.now() - startedAt >= HEALTH_CHECK_MIN_DELAY) { + window.location.reload(); + } + } + }); +} diff --git a/src/api/gramjs/worker/types.ts b/src/api/gramjs/worker/types.ts index b7d897ab3..6200c3991 100644 --- a/src/api/gramjs/worker/types.ts +++ b/src/api/gramjs/worker/types.ts @@ -33,6 +33,9 @@ export type OriginRequest = { messageId?: string; name: keyof Methods; args: MethodArgs; +} | { + type: 'ping'; + messageId?: string; }; export type OriginMessageData = OriginRequest | { diff --git a/src/api/gramjs/worker/worker.ts b/src/api/gramjs/worker/worker.ts index b6d60ee12..3c7720a14 100644 --- a/src/api/gramjs/worker/worker.ts +++ b/src/api/gramjs/worker/worker.ts @@ -81,6 +81,14 @@ onmessage = async (message: OriginMessageEvent) => { cancelApiProgress(callback); } + break; + } + case 'ping': { + sendToOrigin({ + type: 'methodResponse', + messageId: data.messageId!, + }); + break; } }