1 |
|
2 | import { deepCopy } from "@ethersproject/properties";
|
3 | import { fetchJson } from "@ethersproject/web";
|
4 |
|
5 | import { JsonRpcProvider } from "./json-rpc-provider";
|
6 |
|
7 |
|
8 |
|
9 | export 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 |
|
40 | this._pendingBatchAggregator = setTimeout(() => {
|
41 |
|
42 |
|
43 |
|
44 | const batch = this._pendingBatch;
|
45 | this._pendingBatch = null;
|
46 | this._pendingBatchAggregator = null;
|
47 |
|
48 |
|
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 |
|
66 |
|
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 | }
|