Reconnect within MessageReceiver

This commit is contained in:
Fedor Indutny 2021-06-23 07:47:42 -07:00 committed by GitHub
parent 0ec23be91b
commit a6394e0c8b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 40 additions and 24 deletions

View file

@ -43,7 +43,7 @@ import { connectToServerWithStoredCredentials } from './util/connectToServerWith
import * as universalExpireTimer from './util/universalExpireTimer'; import * as universalExpireTimer from './util/universalExpireTimer';
import { isDirectConversation, isGroupV2 } from './util/whatTypeOfConversation'; import { isDirectConversation, isGroupV2 } from './util/whatTypeOfConversation';
import { getSendOptions } from './util/getSendOptions'; import { getSendOptions } from './util/getSendOptions';
import { BackOff } from './util/BackOff'; import { BackOff, FIBONACCI_TIMEOUTS } from './util/BackOff';
import { AppViewType } from './state/ducks/app'; import { AppViewType } from './state/ducks/app';
import { isIncoming } from './state/selectors/message'; import { isIncoming } from './state/selectors/message';
import { actionCreators } from './state/actions'; import { actionCreators } from './state/actions';
@ -113,14 +113,7 @@ export async function startApp(): Promise<void> {
resolveOnAppView = resolve; resolveOnAppView = resolve;
}); });
// Fibonacci timeouts const reconnectBackOff = new BackOff(FIBONACCI_TIMEOUTS);
const reconnectBackOff = new BackOff([
5 * 1000,
10 * 1000,
15 * 1000,
25 * 1000,
40 * 1000,
]);
window.textsecure.protobuf.onLoad(() => { window.textsecure.protobuf.onLoad(() => {
window.storage.onready(() => { window.storage.onready(() => {

View file

@ -186,3 +186,5 @@ export class UnregisteredUserError extends Error {
appendStack(this, httpError); appendStack(this, httpError);
} }
} }
export class ConnectTimeoutError extends Error {}

View file

@ -41,6 +41,7 @@ import {
Sessions, Sessions,
SignedPreKeys, SignedPreKeys,
} from '../LibSignalStores'; } from '../LibSignalStores';
import { BackOff, FIBONACCI_TIMEOUTS } from '../util/BackOff';
import { BatcherType, createBatcher } from '../util/batcher'; import { BatcherType, createBatcher } from '../util/batcher';
import { sleep } from '../util/sleep'; import { sleep } from '../util/sleep';
import { parseIntOrThrow } from '../util/parseIntOrThrow'; import { parseIntOrThrow } from '../util/parseIntOrThrow';
@ -51,6 +52,7 @@ import utils from './Helpers';
import WebSocketResource, { import WebSocketResource, {
IncomingWebSocketRequest, IncomingWebSocketRequest,
} from './WebsocketResources'; } from './WebsocketResources';
import { ConnectTimeoutError } from './Errors';
import * as Bytes from '../Bytes'; import * as Bytes from '../Bytes';
import Crypto from './Crypto'; import Crypto from './Crypto';
import { deriveMasterKeyFromGroupV1, typedArrayToArrayBuffer } from '../Crypto'; import { deriveMasterKeyFromGroupV1, typedArrayToArrayBuffer } from '../Crypto';
@ -80,7 +82,6 @@ const FIXMEU8 = Uint8Array;
const GROUPV1_ID_LENGTH = 16; const GROUPV1_ID_LENGTH = 16;
const GROUPV2_ID_LENGTH = 32; const GROUPV2_ID_LENGTH = 32;
const RETRY_TIMEOUT = 2 * 60 * 1000; const RETRY_TIMEOUT = 2 * 60 * 1000;
const RECONNECT_DELAY = 1 * 1000;
const decryptionErrorTypeSchema = z const decryptionErrorTypeSchema = z
.object({ .object({
@ -229,6 +230,8 @@ class MessageReceiverInner extends EventTarget {
wsr?: WebSocketResource; wsr?: WebSocketResource;
private readonly reconnectBackOff = new BackOff(FIBONACCI_TIMEOUTS);
constructor( constructor(
oldUsername: string, oldUsername: string,
username: string, username: string,
@ -348,6 +351,11 @@ class MessageReceiverInner extends EventTarget {
} catch (error) { } catch (error) {
this.socketStatus = SocketStatus.CLOSED; this.socketStatus = SocketStatus.CLOSED;
if (error instanceof ConnectTimeoutError) {
await this.onclose(-1, 'Connection timed out');
return;
}
const event = new Event('error'); const event = new Event('error');
event.error = error; event.error = error;
await this.dispatchAndWait(event); await this.dispatchAndWait(event);
@ -443,7 +451,7 @@ class MessageReceiverInner extends EventTarget {
async onclose(code: number, reason: string): Promise<void> { async onclose(code: number, reason: string): Promise<void> {
window.log.info( window.log.info(
'websocket closed', 'MessageReceiver: websocket closed',
code, code,
reason || '', reason || '',
'calledClose:', 'calledClose:',
@ -464,12 +472,18 @@ class MessageReceiverInner extends EventTarget {
this.onEmpty(); this.onEmpty();
} }
await sleep(RECONNECT_DELAY); const timeout = this.reconnectBackOff.getAndIncrement();
// Try to reconnect (if there is an error - we'll get an window.log.info(`MessageReceiver: reconnecting after ${timeout}ms`);
// `error` event from `connect()` and hit the retry backoff logic in await sleep(timeout);
// `ts/background.ts`)
// Try to reconnect (if there is an HTTP error - we'll get an
// `error` event from `connect()` and hit the secondary retry backoff
// logic in `ts/background.ts`)
await this.connect(); await this.connect();
// Successfull reconnect, reset the backoff timeouts
this.reconnectBackOff.reset();
} }
checkSocket(): void { checkSocket(): void {

View file

@ -59,6 +59,7 @@ import {
} from '../textsecure.d'; } from '../textsecure.d';
import { SignalService as Proto } from '../protobuf'; import { SignalService as Proto } from '../protobuf';
import { ConnectTimeoutError } from './Errors';
import MessageSender from './SendMessage'; import MessageSender from './SendMessage';
// TODO: remove once we move away from ArrayBuffers // TODO: remove once we move away from ArrayBuffers
@ -305,15 +306,7 @@ async function _connectSocket(
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const timer = setTimeout(() => { const timer = setTimeout(() => {
reject( reject(new ConnectTimeoutError('Connection timed out'));
makeHTTPError(
'_connectSocket: Connection timed out',
-1,
{},
'Connection timed out',
stack
)
);
client.abort(); client.abort();
}, timeout); }, timeout);

View file

@ -1,6 +1,20 @@
// Copyright 2021 Signal Messenger, LLC // Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
const SECOND = 1000;
export const FIBONACCI_TIMEOUTS: ReadonlyArray<number> = [
1 * SECOND,
2 * SECOND,
3 * SECOND,
5 * SECOND,
8 * SECOND,
13 * SECOND,
21 * SECOND,
34 * SECOND,
55 * SECOND,
];
export class BackOff { export class BackOff {
private count = 0; private count = 0;