From d075ec6716b1be45f4a8691aaf15e8172578856d Mon Sep 17 00:00:00 2001 From: Elliot Lee Date: Thu, 3 Oct 2019 00:02:55 -0700 Subject: [PATCH 1/4] Add a 2-second timeout for connect() --- src/common/connection.ts | 31 +++++++++++++++++++++++++++---- test/api-test.js | 4 ++++ yarn.lock | 10 ---------- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/common/connection.ts b/src/common/connection.ts index b8fe47a5..487ca3dd 100644 --- a/src/common/connection.ts +++ b/src/common/connection.ts @@ -8,7 +8,7 @@ import {RippledError, DisconnectedError, NotConnectedError, RippledNotInitializedError} from './errors' export interface ConnectionOptions { - trace?: boolean, + trace?: boolean proxy?: string proxyAuthorization?: string authorization?: string @@ -16,7 +16,8 @@ export interface ConnectionOptions { key?: string passphrase?: string certificate?: string - timeout?: number + timeout?: number, + connectionTimeout?: number } class Connection extends EventEmitter { @@ -43,6 +44,7 @@ class Connection extends EventEmitter { private _onUnexpectedCloseBound: null|((...args: any[]) => void) = null private _fee_base: null|number = null private _fee_ref: null|number = null + private _connectionTimeout: number constructor(url, options: ConnectionOptions = {}) { super() @@ -61,6 +63,7 @@ class Connection extends EventEmitter { this._passphrase = options.passphrase this._certificate = options.certificate this._timeout = options.timeout || (20 * 1000) + this._connectionTimeout = options.connectionTimeout || 2000 } _updateLedgerVersions(data) { @@ -283,7 +286,14 @@ class Connection extends EventEmitter { connect(): Promise { this._clearReconnectTimer() - return new Promise((resolve, reject) => { + let connectFinished = false + const promise = new Promise((resolve, reject) => { + setTimeout(() => { + if (!connectFinished) { + reject(`Error: connect() timed out after ${this._connectionTimeout} ms. ` + + `If your internet connection is working, the rippled server may be blocked or inaccessible.`) + } + }, this._connectionTimeout) if (!this._url) { reject(new ConnectionError( 'Cannot connect because no server was specified')) @@ -311,9 +321,22 @@ class Connection extends EventEmitter { this._onUnexpectedCloseBound = this._onUnexpectedClose.bind(this, true, resolve, reject) this._ws.once('close', this._onUnexpectedCloseBound) - this._ws.once('open', () => this._onOpen().then(resolve, reject)) + this._ws.once('open', () => { + if (connectFinished) { + this._ws.close() + } else { + connectFinished = true + return this._onOpen().then(resolve, reject) + } + }) } }) + promise.then(() => { + connectFinished = true + }, () => { + connectFinished = true + }) + return promise } disconnect(): Promise { diff --git a/test/api-test.js b/test/api-test.js index b20f7a6b..335d5e83 100644 --- a/test/api-test.js +++ b/test/api-test.js @@ -4771,4 +4771,8 @@ describe('RippleAPI - offline', function () { assert.throws(() => new RippleAPI({ server: 'wss//s:1' })); }); + xit('RippleAPI connect() times out after 2 seconds', function () { + // TODO: Use a timer mock like https://jestjs.io/docs/en/timer-mocks + // to test that connect() times out after 2 seconds. + }); }); diff --git a/yarn.lock b/yarn.lock index c53659bf..5b602b2e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4116,16 +4116,6 @@ ripple-binary-codec@^0.2.4: lodash "^4.17.15" ripple-address-codec "^3.0.4" -ripple-hashes@^0.3.4: - version "0.3.4" - resolved "https://registry.yarnpkg.com/ripple-hashes/-/ripple-hashes-0.3.4.tgz#d06f78fc39dde27749b33ad2461b39ba873c94ec" - integrity sha512-u2kgg9Yu9D44HWnC9R2lNg+amVLllJkMQmXZEEM2DAMFXigr4+ph1O8LLxLv+k0fbdjAjos4aUyWwcw6cxzYMw== - dependencies: - bignumber.js "^4.1.0" - create-hash "^1.1.2" - ripple-address-codec "^3.0.4" - ripple-binary-codec "^0.2.4" - ripple-keypairs@^0.10.1: version "0.10.2" resolved "https://registry.yarnpkg.com/ripple-keypairs/-/ripple-keypairs-0.10.2.tgz#b3a1d1e2fca85a11c5224b2a7e6da506c19720d0" From fa7ba9b72b91a7221b89b6f7dbb78fe3b34ac45c Mon Sep 17 00:00:00 2001 From: FKSRipple <56697533+FKSRipple@users.noreply.github.com> Date: Wed, 23 Oct 2019 00:27:17 -0700 Subject: [PATCH 2/4] Update connection.ts --- src/common/connection.ts | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/common/connection.ts b/src/common/connection.ts index 487ca3dd..1727acd5 100644 --- a/src/common/connection.ts +++ b/src/common/connection.ts @@ -286,13 +286,10 @@ class Connection extends EventEmitter { connect(): Promise { this._clearReconnectTimer() - let connectFinished = false - const promise = new Promise((resolve, reject) => { - setTimeout(() => { - if (!connectFinished) { + return new Promise((resolve, reject) => { + let connectTimeout = setTimeout(() => { reject(`Error: connect() timed out after ${this._connectionTimeout} ms. ` + `If your internet connection is working, the rippled server may be blocked or inaccessible.`) - } }, this._connectionTimeout) if (!this._url) { reject(new ConnectionError( @@ -322,21 +319,11 @@ class Connection extends EventEmitter { resolve, reject) this._ws.once('close', this._onUnexpectedCloseBound) this._ws.once('open', () => { - if (connectFinished) { - this._ws.close() - } else { - connectFinished = true - return this._onOpen().then(resolve, reject) - } + clearTimeout(connectTimeout); + return this._onOpen().then(resolve, reject) }) } - }) - promise.then(() => { - connectFinished = true - }, () => { - connectFinished = true - }) - return promise + }); } disconnect(): Promise { From 034f8d41fcf56acd3becfc35dccfdc00d3118ea5 Mon Sep 17 00:00:00 2001 From: "Fred K. Schott" Date: Wed, 23 Oct 2019 00:33:09 -0700 Subject: [PATCH 3/4] remove bad semicolon --- src/common/connection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/connection.ts b/src/common/connection.ts index 95d3669a..69462ad7 100644 --- a/src/common/connection.ts +++ b/src/common/connection.ts @@ -323,7 +323,7 @@ class Connection extends EventEmitter { return this._onOpen().then(resolve, reject) }) } - }); + }) } disconnect(): Promise { From cfdc4752d08bb49d90d39058400a0f0c9924fae4 Mon Sep 17 00:00:00 2001 From: Elliot Lee Date: Wed, 23 Oct 2019 12:25:02 -0700 Subject: [PATCH 4/4] let -> const and reject with error --- src/common/connection.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/connection.ts b/src/common/connection.ts index 69462ad7..9c2579b7 100644 --- a/src/common/connection.ts +++ b/src/common/connection.ts @@ -287,9 +287,9 @@ class Connection extends EventEmitter { connect(): Promise { this._clearReconnectTimer() return new Promise((resolve, reject) => { - let connectTimeout = setTimeout(() => { - reject(`Error: connect() timed out after ${this._connectionTimeout} ms. ` + - `If your internet connection is working, the rippled server may be blocked or inaccessible.`) + const connectTimeout = setTimeout(() => { + reject(new ConnectionError(`Error: connect() timed out after ${this._connectionTimeout} ms. ` + + `If your internet connection is working, the rippled server may be blocked or inaccessible.`)) }, this._connectionTimeout) if (!this._url) { reject(new ConnectionError(