UNPKG

3.38 kBPlain TextView Raw
1
2import { deepCopy } from "@ethersproject/properties";
3import { fetchJson } from "@ethersproject/web";
4
5import { JsonRpcProvider } from "./json-rpc-provider";
6
7// Experimental
8
9export class JsonRpcBatchProvider extends JsonRpcProvider {
10 _pendingBatchAggregator: NodeJS.Timer;
11 _pendingBatch: Array<{
12 request: { method: string, params: Array<any>, id: number, jsonrpc: "2.0" },
13 resolve: (result: any) => void,
14 reject: (error: Error) => void
15 }>;
16
17 send(method: string, params: Array<any>): Promise<any> {
18 const request = {
19 method: method,
20 params: params,
21 id: (this._nextId++),
22 jsonrpc: "2.0"
23 };
24
25 if (this._pendingBatch == null) {
26 this._pendingBatch = [ ];
27 }
28
29 const inflightRequest: any = { request, resolve: null, reject: null };
30
31 const promise = new Promise((resolve, reject) => {
32 inflightRequest.resolve = resolve;
33 inflightRequest.reject = reject;
34 });
35
36 this._pendingBatch.push(inflightRequest);
37
38 if (!this._pendingBatchAggregator) {
39 // Schedule batch for next event loop + short duration
40 this._pendingBatchAggregator = setTimeout(() => {
41
42 // Get teh current batch and clear it, so new requests
43 // go into the next batch
44 const batch = this._pendingBatch;
45 this._pendingBatch = null;
46 this._pendingBatchAggregator = null;
47
48 // Get the request as an array of requests
49 const request = batch.map((inflight) => inflight.request);
50
51 this.emit("debug", {
52 action: "requestBatch",
53 request: deepCopy(request),
54 provider: this
55 });
56
57 return fetchJson(this.connection, JSON.stringify(request)).then((result) => {
58 this.emit("debug", {
59 action: "response",
60 request: request,
61 response: result,
62 provider: this
63 });
64
65 // For each result, feed it to the correct Promise, depending
66 // on whether it was a success or error
67 batch.forEach((inflightRequest, index) => {
68 const payload = result[index];
69 if (payload.error) {
70 const error = new Error(payload.error.message);
71 (<any>error).code = payload.error.code;
72 (<any>error).data = payload.error.data;
73 inflightRequest.reject(error);
74 } else {
75 inflightRequest.resolve(payload.result);
76 }
77 });
78
79 }, (error) => {
80 this.emit("debug", {
81 action: "response",
82 error: error,
83 request: request,
84 provider: this
85 });
86
87 batch.forEach((inflightRequest) => {
88 inflightRequest.reject(error);
89 });
90 });
91
92 }, 10);
93 }
94
95 return promise;
96 }
97}