mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-22 05:05:48 +00:00
add ledger to connection
This commit is contained in:
@@ -36,12 +36,50 @@ export interface ConnectionOptions {
|
|||||||
*/
|
*/
|
||||||
export type ConnectionUserOptions = Partial<ConnectionOptions>
|
export type ConnectionUserOptions = Partial<ConnectionOptions>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ledger is used to store and reference ledger information that has been
|
||||||
|
* captured by the Connection class.
|
||||||
|
*/
|
||||||
|
class Ledger {
|
||||||
|
private availableVersions = new RangeSet()
|
||||||
|
latestVersion: null | number = null
|
||||||
|
feeBase: null | number = null
|
||||||
|
feeRef: null | number = null
|
||||||
|
|
||||||
|
hasVersions(lowVersion: number, highVersion: number): boolean {
|
||||||
|
return this.availableVersions.containsRange(lowVersion, highVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
hasVersion(version: number): boolean {
|
||||||
|
return this.availableVersions.containsValue(version)
|
||||||
|
}
|
||||||
|
|
||||||
|
update(data: {
|
||||||
|
ledger_index?: string
|
||||||
|
validated_ledgers?: string
|
||||||
|
fee_base?: string
|
||||||
|
fee_ref?: string
|
||||||
|
}) {
|
||||||
|
this.latestVersion = Number(data.ledger_index)
|
||||||
|
if (data.validated_ledgers) {
|
||||||
|
this.availableVersions.reset()
|
||||||
|
this.availableVersions.parseAndAddRanges(data.validated_ledgers)
|
||||||
|
} else {
|
||||||
|
this.availableVersions.addValue(this.latestVersion)
|
||||||
|
}
|
||||||
|
if (data.fee_base) {
|
||||||
|
this.feeBase = Number(data.fee_base)
|
||||||
|
}
|
||||||
|
if (data.fee_ref) {
|
||||||
|
this.feeRef = Number(data.fee_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Connection extends EventEmitter {
|
class Connection extends EventEmitter {
|
||||||
private _url: string
|
private _url: string
|
||||||
private _isReady: boolean = false
|
private _isReady: boolean = false
|
||||||
private _ws: null | WebSocket = null
|
private _ws: null | WebSocket = null
|
||||||
protected _ledgerVersion: null | number = null
|
|
||||||
private _availableLedgerVersions = new RangeSet()
|
|
||||||
private _nextRequestID: number = 1
|
private _nextRequestID: number = 1
|
||||||
private _retry: number = 0
|
private _retry: number = 0
|
||||||
private _connectTimer: null | NodeJS.Timeout = null
|
private _connectTimer: null | NodeJS.Timeout = null
|
||||||
@@ -49,16 +87,16 @@ class Connection extends EventEmitter {
|
|||||||
private _heartbeatInterval: null | NodeJS.Timeout = null
|
private _heartbeatInterval: null | NodeJS.Timeout = null
|
||||||
private _onOpenErrorBound: null | null | ((...args: any[]) => void) = null
|
private _onOpenErrorBound: null | null | ((...args: any[]) => void) = null
|
||||||
private _onUnexpectedCloseBound: null | ((...args: any[]) => void) = null
|
private _onUnexpectedCloseBound: null | ((...args: any[]) => void) = null
|
||||||
private _fee_base: null | number = null
|
|
||||||
private _fee_ref: null | number = null
|
|
||||||
|
|
||||||
private _trace: (id: string, message: string) => void = () => {}
|
private _trace: (id: string, message: string) => void = () => {}
|
||||||
private _config: ConnectionOptions
|
private _config: ConnectionOptions
|
||||||
|
private _ledger: Ledger
|
||||||
|
|
||||||
constructor(url?: string, options: ConnectionUserOptions = {}) {
|
constructor(url?: string, options: ConnectionUserOptions = {}) {
|
||||||
super()
|
super()
|
||||||
this.setMaxListeners(Infinity)
|
this.setMaxListeners(Infinity)
|
||||||
this._url = url
|
this._url = url
|
||||||
|
this._ledger = new Ledger()
|
||||||
this._config = {
|
this._config = {
|
||||||
timeout: 20 * 1000,
|
timeout: 20 * 1000,
|
||||||
connectionTimeout: 2 * 1000,
|
connectionTimeout: 2 * 1000,
|
||||||
@@ -71,21 +109,6 @@ class Connection extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateLedgerVersions(data) {
|
|
||||||
this._ledgerVersion = Number(data.ledger_index)
|
|
||||||
if (data.validated_ledgers) {
|
|
||||||
this._availableLedgerVersions.reset()
|
|
||||||
this._availableLedgerVersions.parseAndAddRanges(data.validated_ledgers)
|
|
||||||
} else {
|
|
||||||
this._availableLedgerVersions.addValue(this._ledgerVersion)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateFees(data) {
|
|
||||||
this._fee_base = Number(data.fee_base)
|
|
||||||
this._fee_ref = Number(data.fee_ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
// return value is array of arguments to Connection.emit
|
// return value is array of arguments to Connection.emit
|
||||||
_parseMessage(message): [string, Object] | ['error', string, string, Object] {
|
_parseMessage(message): [string, Object] | ['error', string, string, Object] {
|
||||||
const data = JSON.parse(message)
|
const data = JSON.parse(message)
|
||||||
@@ -101,8 +124,7 @@ class Connection extends EventEmitter {
|
|||||||
// Possible `data.type` values include 'ledgerClosed',
|
// Possible `data.type` values include 'ledgerClosed',
|
||||||
// 'transaction', 'path_find', and many others.
|
// 'transaction', 'path_find', and many others.
|
||||||
if (data.type === 'ledgerClosed') {
|
if (data.type === 'ledgerClosed') {
|
||||||
this._updateLedgerVersions(data)
|
this._ledger.update(data)
|
||||||
this._updateFees(data)
|
|
||||||
}
|
}
|
||||||
return [data.type, data]
|
return [data.type, data]
|
||||||
}
|
}
|
||||||
@@ -212,8 +234,7 @@ class Connection extends EventEmitter {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this._updateLedgerVersions(data)
|
this._ledger.update(data)
|
||||||
this._updateFees(data)
|
|
||||||
this._rebindOnUnexpectedClose()
|
this._rebindOnUnexpectedClose()
|
||||||
|
|
||||||
this._retry = 0
|
this._retry = 0
|
||||||
@@ -432,44 +453,53 @@ class Connection extends EventEmitter {
|
|||||||
return this.request({command: 'ping'}).catch(() => this.reconnect())
|
return this.request({command: 'ping'}).catch(() => this.reconnect())
|
||||||
}
|
}
|
||||||
|
|
||||||
_whenReady<T>(promise: Promise<T>): Promise<T> {
|
/**
|
||||||
|
* Wait for a valid connection before resolving. Useful for deferring methods
|
||||||
|
* until a connection has been established.
|
||||||
|
*/
|
||||||
|
private _waitForReady(): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
promise.catch(reject)
|
|
||||||
if (!this._shouldBeConnected) {
|
if (!this._shouldBeConnected) {
|
||||||
reject(new NotConnectedError())
|
reject(new NotConnectedError())
|
||||||
} else if (this._state === WebSocket.OPEN && this._isReady) {
|
} else if (this._state === WebSocket.OPEN && this._isReady) {
|
||||||
promise.then(resolve, reject)
|
resolve()
|
||||||
} else {
|
} else {
|
||||||
this.once('connected', () => promise.then(resolve, reject))
|
this.once('connected', () => resolve())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getLedgerVersion(): Promise<number> {
|
async getLedgerVersion(): Promise<number> {
|
||||||
return this._whenReady(Promise.resolve(this._ledgerVersion!))
|
await this._waitForReady()
|
||||||
|
return this._ledger.latestVersion!
|
||||||
}
|
}
|
||||||
|
|
||||||
hasLedgerVersions(lowLedgerVersion, highLedgerVersion): Promise<boolean> {
|
async getFeeBase(): Promise<number> {
|
||||||
return this._whenReady(
|
await this._waitForReady()
|
||||||
Promise.resolve(
|
return this._ledger.feeBase!
|
||||||
this._availableLedgerVersions.containsRange(
|
|
||||||
lowLedgerVersion,
|
|
||||||
highLedgerVersion || this._ledgerVersion
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hasLedgerVersion(ledgerVersion): Promise<boolean> {
|
async getFeeRef(): Promise<number> {
|
||||||
return this.hasLedgerVersions(ledgerVersion, ledgerVersion)
|
await this._waitForReady()
|
||||||
|
return this._ledger.feeRef!
|
||||||
}
|
}
|
||||||
|
|
||||||
getFeeBase(): Promise<number> {
|
async hasLedgerVersions(
|
||||||
return this._whenReady(Promise.resolve(Number(this._fee_base)))
|
lowLedgerVersion: number,
|
||||||
|
highLedgerVersion: number | undefined
|
||||||
|
): Promise<boolean> {
|
||||||
|
// You can call hasVersions with a potentially unknown upper limit, which
|
||||||
|
// will just act as a check on the lower limit.
|
||||||
|
if (!highLedgerVersion) {
|
||||||
|
return this.hasLedgerVersion(lowLedgerVersion)
|
||||||
|
}
|
||||||
|
await this._waitForReady()
|
||||||
|
return this._ledger.hasVersions(lowLedgerVersion, highLedgerVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
getFeeRef(): Promise<number> {
|
async hasLedgerVersion(ledgerVersion: number): Promise<boolean> {
|
||||||
return this._whenReady(Promise.resolve(Number(this._fee_ref)))
|
await this._waitForReady()
|
||||||
|
return this._ledger.hasVersion(ledgerVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
_send(message: string): Promise<void> {
|
_send(message: string): Promise<void> {
|
||||||
@@ -543,7 +573,7 @@ class Connection extends EventEmitter {
|
|||||||
// JSON.stringify automatically removes keys with value of 'undefined'
|
// JSON.stringify automatically removes keys with value of 'undefined'
|
||||||
const message = JSON.stringify(Object.assign({}, request, {id}))
|
const message = JSON.stringify(Object.assign({}, request, {id}))
|
||||||
|
|
||||||
this._whenReady(this._send(message))
|
this._send(message)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const delay = timeout || this._config.timeout
|
const delay = timeout || this._config.timeout
|
||||||
timer = setTimeout(() => _reject(new TimeoutError()), delay)
|
timer = setTimeout(() => _reject(new TimeoutError()), delay)
|
||||||
|
|||||||
@@ -79,6 +79,25 @@ describe('Connection', function() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('ledger methods work as expected', async function() {
|
||||||
|
assert.strictEqual(await this.api.connection.getLedgerVersion(), 8819951)
|
||||||
|
assert.strictEqual(
|
||||||
|
await this.api.connection.hasLedgerVersion(8819951),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
assert.strictEqual(
|
||||||
|
await this.api.connection.hasLedgerVersions(8819951, undefined),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
// It would be nice to test a better range, but the mocked ledger only supports this single number
|
||||||
|
assert.strictEqual(
|
||||||
|
await this.api.connection.hasLedgerVersions(8819951, 8819951),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
assert.strictEqual(await this.api.connection.getFeeBase(), 10)
|
||||||
|
assert.strictEqual(await this.api.connection.getFeeRef(), 10)
|
||||||
|
})
|
||||||
|
|
||||||
it('with proxy', function(done) {
|
it('with proxy', function(done) {
|
||||||
if (isBrowser) {
|
if (isBrowser) {
|
||||||
done()
|
done()
|
||||||
|
|||||||
Reference in New Issue
Block a user