From 9580397558d569e7ef5f94fc3b5451d81e5b960c Mon Sep 17 00:00:00 2001 From: "Fred K. Schott" Date: Sun, 15 Dec 2019 14:20:48 -0800 Subject: [PATCH] cleanup the connection config --- src/api.ts | 4 +-- src/common/connection.ts | 75 +++++++++++++++++++--------------------- test/connection-test.ts | 6 ++-- 3 files changed, 41 insertions(+), 44 deletions(-) diff --git a/src/api.ts b/src/api.ts index 34cd970d..ee617111 100644 --- a/src/api.ts +++ b/src/api.ts @@ -75,10 +75,10 @@ import * as schemaValidator from './common/schema-validator' import {getServerInfo, getFee} from './common/serverinfo' import {clamp, renameCounterpartyToIssuer} from './ledger/utils' import {TransactionJSON, Instructions, Prepare} from './transaction/types' -import {ConnectionOptions} from './common/connection' +import {ConnectionUserOptions} from './common/connection' import {isValidXAddress, isValidClassicAddress} from 'ripple-address-codec' -export interface APIOptions extends ConnectionOptions { +export interface APIOptions extends ConnectionUserOptions { server?: string, feeCushion?: number, maxFeeXRP?: string, diff --git a/src/common/connection.ts b/src/common/connection.ts index 5b754e91..8552f392 100644 --- a/src/common/connection.ts +++ b/src/common/connection.ts @@ -7,6 +7,9 @@ import {RippledError, DisconnectedError, NotConnectedError, TimeoutError, ResponseFormatError, ConnectionError, RippledNotInitializedError} from './errors' +/** + * ConnectionOptions is the configuration for the configuration object. + */ export interface ConnectionOptions { trace?: boolean | ((id: string, message: string) => void) proxy?: string @@ -16,21 +19,20 @@ export interface ConnectionOptions { key?: string passphrase?: string certificate?: string - timeout?: number, - connectionTimeout?: number + timeout: number, + connectionTimeout: number } +/** + * ConnectionUserOptions is the user-provided configuration object. All configuration + * is optional, so any ConnectionOptions configuration that has a default value is + * still optional for the user to provide. + */ +export type ConnectionUserOptions = Partial + class Connection extends EventEmitter { private _url: string - private _proxyURL?: string - private _proxyAuthorization?: string - private _authorization?: string - private _trustedCertificates?: string[] - private _key?: string - private _passphrase?: string - private _certificate?: string - private _timeout: number private _isReady: boolean = false private _ws: null|WebSocket = null protected _ledgerVersion: null|number = null @@ -44,28 +46,24 @@ 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 private _trace: (id: string, message: string) => void = () => {} + private _config: ConnectionOptions - constructor(url, options: ConnectionOptions = {}) { + constructor(url?: string, options: ConnectionUserOptions = {}) { super() this.setMaxListeners(Infinity) this._url = url + this._config = { + timeout: (20 * 1000), + connectionTimeout: (2 * 1000), + ...options, + } if (typeof options.trace === 'function') { this._trace = options.trace } else if (options.trace === true) { this._trace = console.log } - this._proxyURL = options.proxy - this._proxyAuthorization = options.proxyAuthorization - this._authorization = options.authorization - this._trustedCertificates = options.trustedCertificates - this._key = options.key - this._passphrase = options.passphrase - this._certificate = options.certificate - this._timeout = options.timeout || (20 * 1000) - this._connectionTimeout = options.connectionTimeout || 2000 } _updateLedgerVersions(data) { @@ -250,17 +248,17 @@ class Connection extends EventEmitter { _createWebSocket(): WebSocket { const options: WebSocket.ClientOptions = {} - if (this._proxyURL !== undefined) { + if (this._config.proxy !== undefined) { const parsedURL = parseUrl(this._url) - const parsedProxyURL = parseUrl(this._proxyURL) + const parsedProxyURL = parseUrl(this._config.proxy) const proxyOverrides = _.omitBy({ secureEndpoint: (parsedURL.protocol === 'wss:'), secureProxy: (parsedProxyURL.protocol === 'https:'), - auth: this._proxyAuthorization, - ca: this._trustedCertificates, - key: this._key, - passphrase: this._passphrase, - cert: this._certificate + auth: this._config.proxyAuthorization, + ca: this._config.trustedCertificates, + key: this._config.key, + passphrase: this._config.passphrase, + cert: this._config.certificate }, _.isUndefined) const proxyOptions = _.assign({}, parsedProxyURL, proxyOverrides) let HttpsProxyAgent @@ -271,15 +269,15 @@ class Connection extends EventEmitter { } options.agent = new HttpsProxyAgent(proxyOptions) } - if (this._authorization !== undefined) { - const base64 = Buffer.from(this._authorization).toString('base64') + if (this._config.authorization !== undefined) { + const base64 = Buffer.from(this._config.authorization).toString('base64') options.headers = {Authorization: `Basic ${base64}`} } const optionsOverrides = _.omitBy({ - ca: this._trustedCertificates, - key: this._key, - passphrase: this._passphrase, - cert: this._certificate + ca: this._config.trustedCertificates, + key: this._config.key, + passphrase: this._config.passphrase, + cert: this._config.certificate }, _.isUndefined) const websocketOptions = _.assign({}, options, optionsOverrides) const websocket = new WebSocket(this._url, null, websocketOptions) @@ -297,12 +295,11 @@ class Connection extends EventEmitter { this._clearHeartbeatInterval() return new Promise((_resolve, reject) => { this._connectTimer = setTimeout(() => { - reject(new ConnectionError(`Error: connect() timed out after ${this._connectionTimeout} ms. ` + + reject(new ConnectionError(`Error: connect() timed out after ${this._config.connectionTimeout} ms. ` + `If your internet connection is working, the rippled server may be blocked or inaccessible.`)) - }, this._connectionTimeout) + }, this._config.connectionTimeout) if (!this._url) { - reject(new ConnectionError( - 'Cannot connect because no server was specified')) + reject(new ConnectionError('Cannot connect because no server was specified')) } const resolve = () => { this._startHeartbeatInterval(); @@ -508,7 +505,7 @@ class Connection extends EventEmitter { const message = JSON.stringify(Object.assign({}, request, {id})) this._whenReady(this._send(message)).then(() => { - const delay = timeout || this._timeout + const delay = timeout || this._config.timeout timer = setTimeout(() => _reject(new TimeoutError()), delay) // Node.js won't exit if a timer is still running, so we tell Node to ignore (Node will still wait for the request to complete) if (timer.unref) { diff --git a/test/connection-test.ts b/test/connection-test.ts index 2e24fc8f..cbc387fb 100644 --- a/test/connection-test.ts +++ b/test/connection-test.ts @@ -31,8 +31,8 @@ describe('Connection', function() { it('default options', function() { const connection: any = new utils.common.Connection('url'); assert.strictEqual(connection._url, 'url'); - assert(_.isUndefined(connection._proxyURL)); - assert(_.isUndefined(connection._authorization)); + assert(_.isUndefined(connection._config.proxy)); + assert(_.isUndefined(connection._config.authorization)); }); describe('trace', () => { @@ -299,7 +299,7 @@ describe('Connection', function() { } } // Set the heartbeat to less than the 1 second ping response - this.api.connection._timeout = 500; + this.api.connection._config.timeout = 500; // Drop the test runner timeout, since this should be a quick test this.timeout(5000); // Hook up a listener for the reconnect event