Skip to content

Commit

Permalink
Added experimental _JsonRpcBatchProvider (#62, #656, #892).
Browse files Browse the repository at this point in the history
  • Loading branch information
ricmoo committed Apr 2, 2021
1 parent 1a7c4e8 commit d55ab6d
Showing 1 changed file with 97 additions and 0 deletions.
97 changes: 97 additions & 0 deletions packages/providers/src.ts/json-rpc-batch-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@

import { deepCopy } from "@ethersproject/properties";
import { fetchJson } from "@ethersproject/web";

import { JsonRpcProvider } from "./json-rpc-provider";

// Experimental

export class _JsonRpcBatchProvider extends JsonRpcProvider {
_pendingBatchAggregator: NodeJS.Timer;
_pendingBatch: Array<{
request: { method: string, params: Array<any>, id: number, jsonrpc: "2.0" },
resolve: (result: any) => void,
reject: (error: Error) => void
}>;

send(method: string, params: Array<any>): Promise<any> {
const request = {
method: method,
params: 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: 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);
(<any>error).code = payload.error.code;
(<any>error).data = payload.error.data;
inflightRequest.reject(error);
} else {
inflightRequest.resolve(payload.result);
}
});

}, (error) => {
this.emit("debug", {
action: "response",
error: error,
request: request,
provider: this
});

batch.forEach((inflightRequest) => {
inflightRequest.reject(error);
});
});

}, 10);
}

return promise;
}
}

0 comments on commit d55ab6d

Please sign in to comment.