cleanup the connection config

This commit is contained in:
Fred K. Schott
2019-12-15 14:20:48 -08:00
parent cf544b74f5
commit 9580397558
3 changed files with 41 additions and 44 deletions

View File

@@ -75,10 +75,10 @@ import * as schemaValidator from './common/schema-validator'
import {getServerInfo, getFee} from './common/serverinfo' import {getServerInfo, getFee} from './common/serverinfo'
import {clamp, renameCounterpartyToIssuer} from './ledger/utils' import {clamp, renameCounterpartyToIssuer} from './ledger/utils'
import {TransactionJSON, Instructions, Prepare} from './transaction/types' import {TransactionJSON, Instructions, Prepare} from './transaction/types'
import {ConnectionOptions} from './common/connection' import {ConnectionUserOptions} from './common/connection'
import {isValidXAddress, isValidClassicAddress} from 'ripple-address-codec' import {isValidXAddress, isValidClassicAddress} from 'ripple-address-codec'
export interface APIOptions extends ConnectionOptions { export interface APIOptions extends ConnectionUserOptions {
server?: string, server?: string,
feeCushion?: number, feeCushion?: number,
maxFeeXRP?: string, maxFeeXRP?: string,

View File

@@ -7,6 +7,9 @@ import {RippledError, DisconnectedError, NotConnectedError,
TimeoutError, ResponseFormatError, ConnectionError, TimeoutError, ResponseFormatError, ConnectionError,
RippledNotInitializedError} from './errors' RippledNotInitializedError} from './errors'
/**
* ConnectionOptions is the configuration for the configuration object.
*/
export interface ConnectionOptions { export interface ConnectionOptions {
trace?: boolean | ((id: string, message: string) => void) trace?: boolean | ((id: string, message: string) => void)
proxy?: string proxy?: string
@@ -16,21 +19,20 @@ export interface ConnectionOptions {
key?: string key?: string
passphrase?: string passphrase?: string
certificate?: string certificate?: string
timeout?: number, timeout: number,
connectionTimeout?: 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<ConnectionOptions>
class Connection extends EventEmitter { class Connection extends EventEmitter {
private _url: string 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 _isReady: boolean = false
private _ws: null|WebSocket = null private _ws: null|WebSocket = null
protected _ledgerVersion: null|number = null protected _ledgerVersion: null|number = null
@@ -44,28 +46,24 @@ class Connection extends EventEmitter {
private _onUnexpectedCloseBound: null|((...args: any[]) => void) = null private _onUnexpectedCloseBound: null|((...args: any[]) => void) = null
private _fee_base: null|number = null private _fee_base: null|number = null
private _fee_ref: null|number = null private _fee_ref: null|number = null
private _connectionTimeout: number
private _trace: (id: string, message: string) => void = () => {} private _trace: (id: string, message: string) => void = () => {}
private _config: ConnectionOptions
constructor(url, options: ConnectionOptions = {}) { constructor(url?: string, options: ConnectionUserOptions = {}) {
super() super()
this.setMaxListeners(Infinity) this.setMaxListeners(Infinity)
this._url = url this._url = url
this._config = {
timeout: (20 * 1000),
connectionTimeout: (2 * 1000),
...options,
}
if (typeof options.trace === 'function') { if (typeof options.trace === 'function') {
this._trace = options.trace this._trace = options.trace
} else if (options.trace === true) { } else if (options.trace === true) {
this._trace = console.log 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) { _updateLedgerVersions(data) {
@@ -250,17 +248,17 @@ class Connection extends EventEmitter {
_createWebSocket(): WebSocket { _createWebSocket(): WebSocket {
const options: WebSocket.ClientOptions = {} const options: WebSocket.ClientOptions = {}
if (this._proxyURL !== undefined) { if (this._config.proxy !== undefined) {
const parsedURL = parseUrl(this._url) const parsedURL = parseUrl(this._url)
const parsedProxyURL = parseUrl(this._proxyURL) const parsedProxyURL = parseUrl(this._config.proxy)
const proxyOverrides = _.omitBy({ const proxyOverrides = _.omitBy({
secureEndpoint: (parsedURL.protocol === 'wss:'), secureEndpoint: (parsedURL.protocol === 'wss:'),
secureProxy: (parsedProxyURL.protocol === 'https:'), secureProxy: (parsedProxyURL.protocol === 'https:'),
auth: this._proxyAuthorization, auth: this._config.proxyAuthorization,
ca: this._trustedCertificates, ca: this._config.trustedCertificates,
key: this._key, key: this._config.key,
passphrase: this._passphrase, passphrase: this._config.passphrase,
cert: this._certificate cert: this._config.certificate
}, _.isUndefined) }, _.isUndefined)
const proxyOptions = _.assign({}, parsedProxyURL, proxyOverrides) const proxyOptions = _.assign({}, parsedProxyURL, proxyOverrides)
let HttpsProxyAgent let HttpsProxyAgent
@@ -271,15 +269,15 @@ class Connection extends EventEmitter {
} }
options.agent = new HttpsProxyAgent(proxyOptions) options.agent = new HttpsProxyAgent(proxyOptions)
} }
if (this._authorization !== undefined) { if (this._config.authorization !== undefined) {
const base64 = Buffer.from(this._authorization).toString('base64') const base64 = Buffer.from(this._config.authorization).toString('base64')
options.headers = {Authorization: `Basic ${base64}`} options.headers = {Authorization: `Basic ${base64}`}
} }
const optionsOverrides = _.omitBy({ const optionsOverrides = _.omitBy({
ca: this._trustedCertificates, ca: this._config.trustedCertificates,
key: this._key, key: this._config.key,
passphrase: this._passphrase, passphrase: this._config.passphrase,
cert: this._certificate cert: this._config.certificate
}, _.isUndefined) }, _.isUndefined)
const websocketOptions = _.assign({}, options, optionsOverrides) const websocketOptions = _.assign({}, options, optionsOverrides)
const websocket = new WebSocket(this._url, null, websocketOptions) const websocket = new WebSocket(this._url, null, websocketOptions)
@@ -297,12 +295,11 @@ class Connection extends EventEmitter {
this._clearHeartbeatInterval() this._clearHeartbeatInterval()
return new Promise<void>((_resolve, reject) => { return new Promise<void>((_resolve, reject) => {
this._connectTimer = setTimeout(() => { 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.`)) `If your internet connection is working, the rippled server may be blocked or inaccessible.`))
}, this._connectionTimeout) }, this._config.connectionTimeout)
if (!this._url) { if (!this._url) {
reject(new ConnectionError( reject(new ConnectionError('Cannot connect because no server was specified'))
'Cannot connect because no server was specified'))
} }
const resolve = () => { const resolve = () => {
this._startHeartbeatInterval(); this._startHeartbeatInterval();
@@ -508,7 +505,7 @@ class Connection extends EventEmitter {
const message = JSON.stringify(Object.assign({}, request, {id})) const message = JSON.stringify(Object.assign({}, request, {id}))
this._whenReady(this._send(message)).then(() => { this._whenReady(this._send(message)).then(() => {
const delay = timeout || this._timeout const delay = timeout || this._config.timeout
timer = setTimeout(() => _reject(new TimeoutError()), delay) 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) // 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) { if (timer.unref) {

View File

@@ -31,8 +31,8 @@ describe('Connection', function() {
it('default options', function() { it('default options', function() {
const connection: any = new utils.common.Connection('url'); const connection: any = new utils.common.Connection('url');
assert.strictEqual(connection._url, 'url'); assert.strictEqual(connection._url, 'url');
assert(_.isUndefined(connection._proxyURL)); assert(_.isUndefined(connection._config.proxy));
assert(_.isUndefined(connection._authorization)); assert(_.isUndefined(connection._config.authorization));
}); });
describe('trace', () => { describe('trace', () => {
@@ -299,7 +299,7 @@ describe('Connection', function() {
} }
} }
// Set the heartbeat to less than the 1 second ping response // 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 // Drop the test runner timeout, since this should be a quick test
this.timeout(5000); this.timeout(5000);
// Hook up a listener for the reconnect event // Hook up a listener for the reconnect event