From 73546f203ad73577ac774e38971662cee15a0417 Mon Sep 17 00:00:00 2001 From: Jackson Mills Date: Tue, 10 May 2022 14:03:07 -0700 Subject: [PATCH] Fix browser infinite disconnect if exception raised during 'connected' (#1981) * Add logic for if disconnect code is undefined --- packages/xrpl/HISTORY.md | 1 + packages/xrpl/src/client/connection.ts | 31 ++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/xrpl/HISTORY.md b/packages/xrpl/HISTORY.md index dcfd6afe..0e8aac9c 100644 --- a/packages/xrpl/HISTORY.md +++ b/packages/xrpl/HISTORY.md @@ -5,6 +5,7 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr ## Unreleased ### Fixed * Client.disconnect() now stops the heartbeat health check as well +* Infinite error/reconnect in browser if an exception was raised during the initial websocket connection event. * Errors during reliable submission with no error message now properly show the preliminary result instead of a type error ## 2.2.3 (2022-05-04) diff --git a/packages/xrpl/src/client/connection.ts b/packages/xrpl/src/client/connection.ts index ff762639..8e1106b9 100644 --- a/packages/xrpl/src/client/connection.ts +++ b/packages/xrpl/src/client/connection.ts @@ -421,6 +421,7 @@ export class Connection extends EventEmitter { * @returns A promise that resolves to void when the connection is fully established. * @throws Error if the websocket initialized is somehow null. */ + // eslint-disable-next-line max-lines-per-function -- Many error code conditionals to check. private async onceOpen(connectionTimeoutID: NodeJS.Timeout): Promise { if (this.ws == null) { throw new XrplError('onceOpen: ws is null') @@ -435,7 +436,7 @@ export class Connection extends EventEmitter { this.emit('error', 'websocket', error.message, error), ) // Handle a closed connection: reconnect if it was unexpected - this.ws.once('close', (code, reason) => { + this.ws.once('close', (code?: number, reason?: Buffer) => { if (this.ws == null) { throw new XrplError('onceClose: ws is null') } @@ -448,9 +449,31 @@ export class Connection extends EventEmitter { ) this.ws.removeAllListeners() this.ws = null - this.emit('disconnected', code) - // If this wasn't a manual disconnect, then lets reconnect ASAP. - if (code !== INTENTIONAL_DISCONNECT_CODE) { + + if (code === undefined) { + const reasonText = reason ? reason.toString() : 'undefined' + // eslint-disable-next-line no-console -- The error is helpful for debugging. + console.error( + `Disconnected but the disconnect code was undefined (The given reason was ${reasonText}).` + + `This could be caused by an exception being thrown during a 'connect' callback. ` + + `Disconnecting with code 1011 to indicate an internal error has occurred.`, + ) + + /* + * Error code 1011 represents an Internal Error according to + * https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code + */ + const internalErrorCode = 1011 + this.emit('disconnected', internalErrorCode) + } else { + this.emit('disconnected', code) + } + + /* + * If this wasn't a manual disconnect, then lets reconnect ASAP. + * Code can be undefined if there's an exception while connecting. + */ + if (code !== INTENTIONAL_DISCONNECT_CODE && code !== undefined) { this.intentionalDisconnect() } })