-
Notifications
You must be signed in to change notification settings - Fork 753
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
200 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { BatchClientOptions } from './interface'; | ||
import { DelayedAction } from './delayedAction'; | ||
import { stringify } from '../utils/json'; | ||
import { RPC } from '../types'; | ||
import { JRPC } from '../types/api'; | ||
|
||
export class BatchClient extends DelayedAction { | ||
public nodeUrl: string; | ||
|
||
public headers: object; | ||
|
||
public interval: number; | ||
|
||
public requestId: number = 0; | ||
|
||
private pendingRequests: Record<string | number, JRPC.RequestBody> = {}; | ||
|
||
private batchPromise?: Promise<any>; | ||
|
||
constructor(options: BatchClientOptions) { | ||
super(options.interval); | ||
|
||
this.nodeUrl = options.nodeUrl; | ||
this.headers = options.headers; | ||
this.interval = options.interval; | ||
} | ||
|
||
private addPendingRequest<T extends keyof RPC.Methods>( | ||
method: T, | ||
params?: RPC.Methods[T]['params'], | ||
id?: string | number | ||
) { | ||
const request: JRPC.RequestBody = { | ||
id: id ?? `batched_${(this.requestId += 1)}`, | ||
jsonrpc: '2.0', | ||
method, | ||
params: params ?? undefined, | ||
}; | ||
|
||
this.pendingRequests[request.id] = request; | ||
|
||
return request.id; | ||
} | ||
|
||
private async sendBatch(requests: JRPC.RequestBody[]) { | ||
const raw = await fetch(this.nodeUrl, { | ||
method: 'POST', | ||
body: stringify(requests), | ||
headers: this.headers as Record<string, string>, | ||
}); | ||
|
||
return raw.json(); | ||
} | ||
|
||
public async fetch<T extends keyof RPC.Methods>( | ||
method: T, | ||
params?: RPC.Methods[T]['params'], | ||
id?: string | number | ||
) { | ||
const requestId = this.addPendingRequest(method, params, id); | ||
|
||
await this.wait(); | ||
|
||
const requests = this.pendingRequests; | ||
this.pendingRequests = {}; | ||
|
||
if (!this.batchPromise) { | ||
this.batchPromise = this.sendBatch(Object.values(requests)); | ||
} | ||
const results = await this.batchPromise; | ||
this.batchPromise = undefined; | ||
|
||
return results.find((result: any) => result.id === requestId); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
export class DelayedAction { | ||
private delay: number; | ||
|
||
private timer: NodeJS.Timeout | null; | ||
|
||
private promise?: Promise<void>; | ||
|
||
private promiseResolve?: () => void; | ||
|
||
constructor(delay: number = 5000) { | ||
this.delay = delay; | ||
this.timer = null; | ||
} | ||
|
||
/** | ||
* Waits for the delay to pass, then resolves the promise. | ||
* All calls to this method will return the same promise until the delay has passed | ||
* | ||
* @returns {Promise<void>} | ||
*/ | ||
public async wait(): Promise<void> { | ||
// If the promise is not set, create a new one and store the resolve function | ||
if (!this.promise || !this.promiseResolve) { | ||
this.promise = new Promise((resolve) => { | ||
this.promiseResolve = resolve; | ||
}); | ||
} | ||
|
||
if (this.timer) { | ||
clearTimeout(this.timer); | ||
this.timer = null; | ||
} | ||
|
||
this.timer = setTimeout(() => { | ||
if (this.promiseResolve) { | ||
this.promiseResolve(); | ||
|
||
// Reset the promise and resolve function so that a new promise is created next time | ||
this.promise = undefined; | ||
this.promiseResolve = undefined; | ||
} | ||
}, this.delay); | ||
|
||
return this.promise; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './interface'; | ||
export * from './default'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { RPC } from '../types'; | ||
import { JRPC } from '../types/api'; | ||
|
||
export type BatchClientOptions = { | ||
nodeUrl: string; | ||
headers: object; | ||
interval: number; | ||
}; | ||
|
||
export abstract class BatchClientInterface { | ||
/** | ||
* Fetch batched JSON-RPC requests | ||
* | ||
* @param body - JSON-RPC request body | ||
* @returns JSON-RPC response | ||
*/ | ||
public abstract fetch<T extends keyof RPC.Methods>( | ||
method: T, | ||
params?: RPC.Methods[T]['params'], | ||
id?: string | number | ||
): Promise< | ||
JRPC.ResponseBody & | ||
( | ||
| { | ||
result?: RPC.Methods[T]['result']; | ||
} | ||
| { | ||
error?: RPC.Methods[T] extends { error: infer E } ? E : never; | ||
} | ||
) | ||
>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters