From d1a2553bc2c1444357c656aceda3ff3752dd8c4a Mon Sep 17 00:00:00 2001 From: Georges KABBOUCHI Date: Wed, 25 Oct 2023 17:30:50 +0300 Subject: [PATCH] 0.5.3 --- package.json | 2 +- src/providers/json-rpc-provider.ts | 87 ++++++++++++++++++++++++++++++ src/providers/retry-provider.ts | 41 +++++++++++++- 3 files changed, 128 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2a25ade..44426d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@instadapp/utils", - "version": "0.5.2", + "version": "0.5.3", "description": "", "repository": "instadapp/utils", "license": "MIT", diff --git a/src/providers/json-rpc-provider.ts b/src/providers/json-rpc-provider.ts index d476a4b..008581b 100644 --- a/src/providers/json-rpc-provider.ts +++ b/src/providers/json-rpc-provider.ts @@ -819,3 +819,90 @@ export class JsonRpcBatchProvider extends JsonRpcProvider { return promise } } + +export class StaticJsonRpcBatchProvider extends StaticJsonRpcProvider { + _pendingBatchAggregator: NodeJS.Timer + _pendingBatch: Array<{ + request: { method: string, params: Array, id: number, jsonrpc: '2.0' }, + resolve: (result: any) => void, + reject: (error: Error) => void + }> + + send (method: string, params: Array): Promise { + const request = { + method, + params, + id: (this._nextId++), + jsonrpc: '2.0' + } + + if (this._pendingBatch == null) { + this._pendingBatch = [] + } + + const inflightRequest: any = { request, resolve: null, reject: null } + + const promise = new Promise((resolve, reject) => { + inflightRequest.resolve = resolve + inflightRequest.reject = reject + }) + + this._pendingBatch.push(inflightRequest) + + if (!this._pendingBatchAggregator) { + // Schedule batch for next event loop + short duration + this._pendingBatchAggregator = setTimeout(() => { + // Get teh current batch and clear it, so new requests + // go into the next batch + const batch = this._pendingBatch + this._pendingBatch = null + this._pendingBatchAggregator = null + + // Get the request as an array of requests + const request = batch.map(inflight => inflight.request) + + this.emit('debug', { + action: 'requestBatch', + request: deepCopy(request), + provider: this + }) + + return fetchJson(this.connection, JSON.stringify(request)).then((result) => { + this.emit('debug', { + action: 'response', + request, + response: result, + provider: this + }) + + // For each result, feed it to the correct Promise, depending + // on whether it was a success or error + batch.forEach((inflightRequest, index) => { + const payload = result[index] + if (payload.error) { + const error = new Error(payload.error.message); + (error).code = payload.error.code; + (error).data = payload.error.data + inflightRequest.reject(error) + } else { + inflightRequest.resolve(payload.result) + } + }) + }, (error) => { + this.emit('debug', { + action: 'response', + error, + request, + provider: this + }) + + batch.forEach((inflightRequest) => { + inflightRequest.reject(error) + }) + }) + }, 10) + } + + return promise + } +} diff --git a/src/providers/retry-provider.ts b/src/providers/retry-provider.ts index 008b9a1..96da030 100644 --- a/src/providers/retry-provider.ts +++ b/src/providers/retry-provider.ts @@ -1,5 +1,5 @@ import { retry } from '../promises' -import { JsonRpcProvider, StaticJsonRpcProvider, JsonRpcBatchProvider } from './json-rpc-provider' +import { JsonRpcProvider, StaticJsonRpcProvider, JsonRpcBatchProvider, StaticJsonRpcBatchProvider } from './json-rpc-provider' export class JsonRpcRetryProvider extends JsonRpcProvider { urls: string[] @@ -117,3 +117,42 @@ export class StaticJsonRpcRetryProvider extends StaticJsonRpcProvider { }) } } + +export class StaticJsonRpcRetryBatchProvider extends StaticJsonRpcBatchProvider { + urls: string[] + urlIndex: number = 0 + timeouts: number[] = [5_000, 10_000, 15_000] + delay: number = 300 + + constructor (urls: string | string[], options?: { timeouts?: number[], delay?: number }) { + urls = Array.isArray(urls) ? urls : [urls] + + super(urls[0]) + + this.urls = urls + this.urlIndex = 0 + + if (options && options.timeouts) { + this.timeouts = options.timeouts + } + + if (options && options.delay) { + this.delay = options.delay + } + + Object.setPrototypeOf(this, StaticJsonRpcRetryProvider.prototype) + } + + public send (method: string, params: Array): Promise { + const operation = () => super.send(method, params) + + return retry(operation, { + timeouts: this.timeouts, + delay: this.delay, + onRetry: () => { + this.urlIndex = (this.urlIndex + 1) % this.urls.length + this.connection.url = this.urls[this.urlIndex] + } + }) + } +}