@pezkuwi/rpc-provider 16.5.17 → 16.5.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/LICENSE +201 -0
- package/build/README.md +68 -0
- package/build/bizinikiwi-connect/Health.js +259 -0
- package/build/bizinikiwi-connect/index.js +319 -0
- package/build/bundle.js +5 -0
- package/build/cjs/bizinikiwi-connect/Health.d.ts +7 -0
- package/build/cjs/bizinikiwi-connect/Health.js +264 -0
- package/build/cjs/bizinikiwi-connect/index.d.ts +22 -0
- package/build/cjs/bizinikiwi-connect/index.js +323 -0
- package/build/cjs/bizinikiwi-connect/types.d.ts +12 -0
- package/build/cjs/bizinikiwi-connect/types.js +2 -0
- package/build/cjs/bundle.d.ts +5 -0
- package/build/cjs/bundle.js +14 -0
- package/build/cjs/coder/error.js +53 -0
- package/build/cjs/coder/index.js +63 -0
- package/build/cjs/defaults.js +8 -0
- package/build/cjs/http/index.js +196 -0
- package/build/cjs/http/types.js +2 -0
- package/build/cjs/index.js +5 -0
- package/build/cjs/lru.js +150 -0
- package/build/cjs/mock/index.js +196 -0
- package/build/cjs/mock/mockHttp.js +17 -0
- package/build/cjs/mock/mockWs.js +47 -0
- package/build/cjs/mock/types.js +2 -0
- package/build/cjs/packageDetect.d.ts +1 -0
- package/build/cjs/packageInfo.js +4 -0
- package/build/cjs/types.js +2 -0
- package/build/cjs/ws/errors.js +41 -0
- package/build/cjs/ws/index.js +529 -0
- package/build/coder/error.d.ts +29 -0
- package/build/coder/error.js +50 -0
- package/build/coder/index.d.ts +8 -0
- package/build/coder/index.js +58 -0
- package/build/defaults.d.ts +5 -0
- package/build/defaults.js +6 -0
- package/build/http/index.d.ts +81 -0
- package/build/http/index.js +191 -0
- package/build/http/types.d.ts +7 -0
- package/build/http/types.js +1 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +2 -0
- package/build/lru.d.ts +15 -0
- package/build/lru.js +146 -0
- package/build/mock/index.d.ts +35 -0
- package/build/mock/index.js +191 -0
- package/build/mock/mockHttp.d.ts +9 -0
- package/build/mock/mockHttp.js +12 -0
- package/build/mock/mockWs.d.ts +26 -0
- package/build/mock/mockWs.js +43 -0
- package/build/mock/types.d.ts +23 -0
- package/build/mock/types.js +1 -0
- package/build/package.json +344 -0
- package/build/packageDetect.d.ts +1 -0
- package/build/packageDetect.js +4 -0
- package/build/packageInfo.d.ts +6 -0
- package/build/packageInfo.js +1 -0
- package/build/types.d.ts +85 -0
- package/build/types.js +1 -0
- package/build/ws/errors.d.ts +1 -0
- package/build/ws/errors.js +38 -0
- package/build/ws/index.d.ts +121 -0
- package/build/ws/index.js +524 -0
- package/build-deno/README.md +66 -0
- package/build-deno/bizinikiwi-connect/Health.ts +323 -0
- package/build-deno/bizinikiwi-connect/index.ts +417 -0
- package/build-deno/bizinikiwi-connect/types.ts +14 -0
- package/build-deno/bundle.ts +6 -0
- package/build-deno/coder/error.ts +64 -0
- package/build-deno/coder/index.ts +86 -0
- package/build-deno/defaults.ts +8 -0
- package/build-deno/http/index.ts +236 -0
- package/build-deno/http/types.ts +9 -0
- package/build-deno/index.ts +4 -0
- package/build-deno/lru.ts +189 -0
- package/build-deno/mock/index.ts +257 -0
- package/build-deno/mock/mockHttp.ts +33 -0
- package/build-deno/mock/mockWs.ts +87 -0
- package/build-deno/mock/types.ts +34 -0
- package/build-deno/mod.ts +2 -0
- package/build-deno/packageDetect.ts +8 -0
- package/build-deno/packageInfo.ts +3 -0
- package/build-deno/types.ts +99 -0
- package/build-deno/ws/errors.ts +38 -0
- package/build-deno/ws/index.ts +650 -0
- package/build-tsc-cjs/packageDetect.js +6 -0
- package/{cjs → build-tsc-cjs}/packageInfo.js +1 -1
- package/{packageInfo.js → build-tsc-esm/packageInfo.js} +1 -1
- package/package.json +16 -16
- package/src/bizinikiwi-connect/Health.ts +325 -0
- package/src/bizinikiwi-connect/index.spec.ts +675 -0
- package/src/bizinikiwi-connect/index.ts +427 -0
- package/src/bizinikiwi-connect/types.ts +16 -0
- package/src/bundle.ts +8 -0
- package/src/coder/decodeResponse.spec.ts +70 -0
- package/src/coder/encodeJson.spec.ts +20 -0
- package/src/coder/encodeObject.spec.ts +25 -0
- package/src/coder/error.spec.ts +111 -0
- package/src/coder/error.ts +66 -0
- package/src/coder/index.ts +88 -0
- package/src/defaults.ts +10 -0
- package/src/http/index.spec.ts +72 -0
- package/src/http/index.ts +238 -0
- package/src/http/send.spec.ts +61 -0
- package/src/http/types.ts +11 -0
- package/src/index.ts +6 -0
- package/src/lru.spec.ts +74 -0
- package/src/lru.ts +197 -0
- package/src/mock/index.ts +259 -0
- package/src/mock/mockHttp.ts +35 -0
- package/src/mock/mockWs.ts +92 -0
- package/src/mock/on.spec.ts +43 -0
- package/src/mock/send.spec.ts +38 -0
- package/src/mock/subscribe.spec.ts +81 -0
- package/src/mock/types.ts +36 -0
- package/src/mock/unsubscribe.spec.ts +57 -0
- package/src/mod.ts +4 -0
- package/src/packageDetect.ts +12 -0
- package/src/packageInfo.ts +6 -0
- package/src/types.ts +101 -0
- package/src/ws/connect.spec.ts +167 -0
- package/src/ws/errors.ts +41 -0
- package/src/ws/index.spec.ts +97 -0
- package/src/ws/index.ts +652 -0
- package/src/ws/send.spec.ts +126 -0
- package/src/ws/state.spec.ts +20 -0
- package/src/ws/subscribe.spec.ts +68 -0
- package/src/ws/unsubscribe.spec.ts +100 -0
- package/tsconfig.build.json +17 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.spec.json +18 -0
- package/tsconfig.spec.tsbuildinfo +1 -0
- /package/{cjs → build}/bizinikiwi-connect/Health.d.ts +0 -0
- /package/{cjs → build}/bizinikiwi-connect/index.d.ts +0 -0
- /package/{cjs → build}/bizinikiwi-connect/types.d.ts +0 -0
- /package/{packageDetect.d.ts → build/bizinikiwi-connect/types.js} +0 -0
- /package/{cjs → build}/bundle.d.ts +0 -0
- /package/{coder → build/cjs/coder}/error.d.ts +0 -0
- /package/{coder → build/cjs/coder}/index.d.ts +0 -0
- /package/{defaults.d.ts → build/cjs/defaults.d.ts} +0 -0
- /package/{http → build/cjs/http}/index.d.ts +0 -0
- /package/{http → build/cjs/http}/types.d.ts +0 -0
- /package/{index.d.ts → build/cjs/index.d.ts} +0 -0
- /package/{lru.d.ts → build/cjs/lru.d.ts} +0 -0
- /package/{mock → build/cjs/mock}/index.d.ts +0 -0
- /package/{mock → build/cjs/mock}/mockHttp.d.ts +0 -0
- /package/{mock → build/cjs/mock}/mockWs.d.ts +0 -0
- /package/{mock → build/cjs/mock}/types.d.ts +0 -0
- /package/{cjs → build/cjs}/package.json +0 -0
- /package/{cjs → build/cjs}/packageDetect.js +0 -0
- /package/{packageInfo.d.ts → build/cjs/packageInfo.d.ts} +0 -0
- /package/{types.d.ts → build/cjs/types.d.ts} +0 -0
- /package/{ws → build/cjs/ws}/errors.d.ts +0 -0
- /package/{ws → build/cjs/ws}/index.d.ts +0 -0
- /package/{bizinikiwi-connect → build-tsc/bizinikiwi-connect}/Health.d.ts +0 -0
- /package/{bizinikiwi-connect → build-tsc/bizinikiwi-connect}/index.d.ts +0 -0
- /package/{bizinikiwi-connect → build-tsc/bizinikiwi-connect}/types.d.ts +0 -0
- /package/{bundle.d.ts → build-tsc/bundle.d.ts} +0 -0
- /package/{cjs → build-tsc}/coder/error.d.ts +0 -0
- /package/{cjs → build-tsc}/coder/index.d.ts +0 -0
- /package/{cjs → build-tsc}/defaults.d.ts +0 -0
- /package/{cjs → build-tsc}/http/index.d.ts +0 -0
- /package/{cjs → build-tsc}/http/types.d.ts +0 -0
- /package/{cjs → build-tsc}/index.d.ts +0 -0
- /package/{cjs → build-tsc}/lru.d.ts +0 -0
- /package/{cjs → build-tsc}/mock/index.d.ts +0 -0
- /package/{cjs → build-tsc}/mock/mockHttp.d.ts +0 -0
- /package/{cjs → build-tsc}/mock/mockWs.d.ts +0 -0
- /package/{cjs → build-tsc}/mock/types.d.ts +0 -0
- /package/{cjs → build-tsc}/packageDetect.d.ts +0 -0
- /package/{cjs → build-tsc}/packageInfo.d.ts +0 -0
- /package/{cjs → build-tsc}/types.d.ts +0 -0
- /package/{cjs → build-tsc}/ws/errors.d.ts +0 -0
- /package/{cjs → build-tsc}/ws/index.d.ts +0 -0
- /package/{cjs → build-tsc-cjs}/bizinikiwi-connect/Health.js +0 -0
- /package/{cjs → build-tsc-cjs}/bizinikiwi-connect/index.js +0 -0
- /package/{cjs → build-tsc-cjs}/bizinikiwi-connect/types.js +0 -0
- /package/{cjs → build-tsc-cjs}/bundle.js +0 -0
- /package/{cjs → build-tsc-cjs}/coder/error.js +0 -0
- /package/{cjs → build-tsc-cjs}/coder/index.js +0 -0
- /package/{cjs → build-tsc-cjs}/defaults.js +0 -0
- /package/{cjs → build-tsc-cjs}/http/index.js +0 -0
- /package/{cjs → build-tsc-cjs}/http/types.js +0 -0
- /package/{cjs → build-tsc-cjs}/index.js +0 -0
- /package/{cjs → build-tsc-cjs}/lru.js +0 -0
- /package/{cjs → build-tsc-cjs}/mock/index.js +0 -0
- /package/{cjs → build-tsc-cjs}/mock/mockHttp.js +0 -0
- /package/{cjs → build-tsc-cjs}/mock/mockWs.js +0 -0
- /package/{cjs → build-tsc-cjs}/mock/types.js +0 -0
- /package/{cjs → build-tsc-cjs}/types.js +0 -0
- /package/{cjs → build-tsc-cjs}/ws/errors.js +0 -0
- /package/{cjs → build-tsc-cjs}/ws/index.js +0 -0
- /package/{bizinikiwi-connect → build-tsc-esm/bizinikiwi-connect}/Health.js +0 -0
- /package/{bizinikiwi-connect → build-tsc-esm/bizinikiwi-connect}/index.js +0 -0
- /package/{bizinikiwi-connect → build-tsc-esm/bizinikiwi-connect}/types.js +0 -0
- /package/{bundle.js → build-tsc-esm/bundle.js} +0 -0
- /package/{coder → build-tsc-esm/coder}/error.js +0 -0
- /package/{coder → build-tsc-esm/coder}/index.js +0 -0
- /package/{defaults.js → build-tsc-esm/defaults.js} +0 -0
- /package/{http → build-tsc-esm/http}/index.js +0 -0
- /package/{http → build-tsc-esm/http}/types.js +0 -0
- /package/{index.js → build-tsc-esm/index.js} +0 -0
- /package/{lru.js → build-tsc-esm/lru.js} +0 -0
- /package/{mock → build-tsc-esm/mock}/index.js +0 -0
- /package/{mock → build-tsc-esm/mock}/mockHttp.js +0 -0
- /package/{mock → build-tsc-esm/mock}/mockWs.js +0 -0
- /package/{mock → build-tsc-esm/mock}/types.js +0 -0
- /package/{packageDetect.js → build-tsc-esm/packageDetect.js} +0 -0
- /package/{types.js → build-tsc-esm/types.js} +0 -0
- /package/{ws → build-tsc-esm/ws}/errors.js +0 -0
- /package/{ws → build-tsc-esm/ws}/index.js +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# @pezkuwi/rpc-provider
|
|
2
|
+
|
|
3
|
+
Generic transport providers to handle the transport of method calls to and from Pezkuwi clients from applications interacting with it. It provides an interface to making RPC calls and is generally, unless you are operating at a low-level and taking care of encoding and decoding of parameters/results, it won't be directly used, rather only passed to a higher-level interface.
|
|
4
|
+
|
|
5
|
+
## Provider Selection
|
|
6
|
+
|
|
7
|
+
There are three flavours of the providers provided, one allowing for using HTTP as a transport mechanism, the other using WebSockets, and the third one uses bizinikiwi light-client through @bizinikiwi/connect. It is generally recommended to use the [[WsProvider]] since in addition to standard calls, it allows for subscriptions where all changes to state can be pushed from the node to the client.
|
|
8
|
+
|
|
9
|
+
All providers are usable (as is the API), in both browser-based and Node.js environments. Polyfills for unsupported functionality are automatically applied based on feature-detection.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Installation -
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
yarn add @pezkuwi/rpc-provider
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
WebSocket Initialization -
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
import { WsProvider } from 'https://deno.land/x/pezkuwi/rpc-provider/mod.ts';
|
|
23
|
+
|
|
24
|
+
const provider = new WsProvider('ws://127.0.0.1:9944');
|
|
25
|
+
const version = await provider.send('client_version', []);
|
|
26
|
+
|
|
27
|
+
console.log('client version', version);
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
HTTP Initialization -
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
import { HttpProvider } from 'https://deno.land/x/pezkuwi/rpc-provider/mod.ts';
|
|
34
|
+
|
|
35
|
+
const provider = new HttpProvider('http://127.0.0.1:9933');
|
|
36
|
+
const version = await provider.send('chain_getBlockHash', []);
|
|
37
|
+
|
|
38
|
+
console.log('latest block Hash', hash);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
@bizinikiwi/connect Initialization -
|
|
42
|
+
|
|
43
|
+
Instantiating a Provider for the Pezkuwi Relay Chain:
|
|
44
|
+
```javascript
|
|
45
|
+
import { ScProvider } from 'https://deno.land/x/pezkuwi/rpc-provider/mod.ts';
|
|
46
|
+
import * as Sc from 'https://esm.sh/@bizinikiwi/connect@2.1.9';
|
|
47
|
+
|
|
48
|
+
const provider = new ScProvider(Sc, Sc.WellKnownChain.pezkuwi);
|
|
49
|
+
|
|
50
|
+
await provider.connect();
|
|
51
|
+
|
|
52
|
+
const version = await provider.send('chain_getBlockHash', []);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Instantiating a Provider for a Pezkuwi teyrchain:
|
|
56
|
+
```javascript
|
|
57
|
+
import { ScProvider } from 'https://deno.land/x/pezkuwi/rpc-provider/mod.ts';
|
|
58
|
+
import * as Sc from 'https://esm.sh/@bizinikiwi/connect@2.1.9';
|
|
59
|
+
|
|
60
|
+
const pezkuwiProvider = new ScProvider(Sc, Sc.WellKnownChain.pezkuwi);
|
|
61
|
+
const teyrchainProvider = new ScProvider(Sc, teyrchainSpec, pezkuwiProvider);
|
|
62
|
+
|
|
63
|
+
await teyrchainProvider.connect();
|
|
64
|
+
|
|
65
|
+
const version = await teyrchainProvider.send('chain_getBlockHash', []);
|
|
66
|
+
```
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
|
|
2
|
+
import type { HealthChecker, SmoldotHealth } from './types.ts';
|
|
3
|
+
|
|
4
|
+
import { stringify } from 'https://deno.land/x/pezkuwi/util/mod.ts';
|
|
5
|
+
|
|
6
|
+
interface JSONRequest {
|
|
7
|
+
id: string;
|
|
8
|
+
jsonrpc: '2.0',
|
|
9
|
+
method: string;
|
|
10
|
+
params: unknown[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
* Creates a new health checker.
|
|
15
|
+
*
|
|
16
|
+
* The role of the health checker is to report to the user the health of a smoldot chain.
|
|
17
|
+
*
|
|
18
|
+
* In order to use it, start by creating a health checker, and call `setSendJsonRpc` to set the
|
|
19
|
+
* way to send a JSON-RPC request to a chain. The health checker is disabled by default. Use
|
|
20
|
+
* `start()` in order to start the health checks. The `start()` function must be passed a callback called
|
|
21
|
+
* when an update to the health of the node is available.
|
|
22
|
+
*
|
|
23
|
+
* In order to send a JSON-RPC request to the chain, you **must** use the `sendJsonRpc` function
|
|
24
|
+
* of the health checker. The health checker rewrites the `id` of the requests it receives.
|
|
25
|
+
*
|
|
26
|
+
* When the chain send a JSON-RPC response, it must be passed to `responsePassThrough()`. This
|
|
27
|
+
* function intercepts the responses destined to the requests that have been emitted by the health
|
|
28
|
+
* checker and returns `null`. If the response doesn't concern the health checker, the response is
|
|
29
|
+
* simply returned by the function.
|
|
30
|
+
*
|
|
31
|
+
* # How it works
|
|
32
|
+
*
|
|
33
|
+
* The health checker periodically calls the `system_health` JSON-RPC call in order to determine
|
|
34
|
+
* the health of the chain.
|
|
35
|
+
*
|
|
36
|
+
* In addition to this, as long as the health check reports that `isSyncing` is `true`, the
|
|
37
|
+
* health checker also maintains a subscription to new best blocks using `chain_subscribeNewHeads`.
|
|
38
|
+
* Whenever a new block is notified, a health check is performed immediately in order to determine
|
|
39
|
+
* whether `isSyncing` has changed to `false`.
|
|
40
|
+
*
|
|
41
|
+
* Thanks to this subscription, the latency of the report of the switch from `isSyncing: true` to
|
|
42
|
+
* `isSyncing: false` is very low.
|
|
43
|
+
*
|
|
44
|
+
*/
|
|
45
|
+
export function healthChecker (): HealthChecker {
|
|
46
|
+
// `null` if health checker is not started.
|
|
47
|
+
let checker: null | InnerChecker = null;
|
|
48
|
+
let sendJsonRpc: null | ((request: string) => void) = null;
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
responsePassThrough: (jsonRpcResponse) => {
|
|
52
|
+
if (checker === null) {
|
|
53
|
+
return jsonRpcResponse;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return checker.responsePassThrough(jsonRpcResponse);
|
|
57
|
+
},
|
|
58
|
+
sendJsonRpc: (request) => {
|
|
59
|
+
if (!sendJsonRpc) {
|
|
60
|
+
throw new Error('setSendJsonRpc must be called before sending requests');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (checker === null) {
|
|
64
|
+
sendJsonRpc(request);
|
|
65
|
+
} else {
|
|
66
|
+
checker.sendJsonRpc(request);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
setSendJsonRpc: (cb) => {
|
|
70
|
+
sendJsonRpc = cb;
|
|
71
|
+
},
|
|
72
|
+
start: (healthCallback) => {
|
|
73
|
+
if (checker !== null) {
|
|
74
|
+
throw new Error("Can't start the health checker multiple times in parallel");
|
|
75
|
+
} else if (!sendJsonRpc) {
|
|
76
|
+
throw new Error('setSendJsonRpc must be called before starting the health checks');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
checker = new InnerChecker(healthCallback, sendJsonRpc);
|
|
80
|
+
checker.update(true);
|
|
81
|
+
},
|
|
82
|
+
stop: () => {
|
|
83
|
+
if (checker === null) {
|
|
84
|
+
return;
|
|
85
|
+
} // Already stopped.
|
|
86
|
+
|
|
87
|
+
checker.destroy();
|
|
88
|
+
checker = null;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
class InnerChecker {
|
|
94
|
+
#healthCallback: (health: SmoldotHealth) => void;
|
|
95
|
+
#currentHealthCheckId: string | null = null;
|
|
96
|
+
#currentHealthTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
97
|
+
#currentSubunsubRequestId: string | null = null;
|
|
98
|
+
#currentSubscriptionId: string | null = null;
|
|
99
|
+
#requestToSmoldot: (request: JSONRequest) => void;
|
|
100
|
+
#isSyncing = false;
|
|
101
|
+
#nextRequestId = 0;
|
|
102
|
+
|
|
103
|
+
constructor (healthCallback: (health: SmoldotHealth) => void, requestToSmoldot: (request: string) => void) {
|
|
104
|
+
this.#healthCallback = healthCallback;
|
|
105
|
+
this.#requestToSmoldot = (request: JSONRequest) => requestToSmoldot(stringify(request));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
sendJsonRpc = (request: string): void => {
|
|
109
|
+
// Replace the `id` in the request to prefix the request ID with `extern:`.
|
|
110
|
+
let parsedRequest: JSONRequest;
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
parsedRequest = JSON.parse(request) as JSONRequest;
|
|
114
|
+
} catch {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (parsedRequest.id) {
|
|
119
|
+
const newId = 'extern:' + stringify(parsedRequest.id);
|
|
120
|
+
|
|
121
|
+
parsedRequest.id = newId;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.#requestToSmoldot(parsedRequest);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
responsePassThrough = (jsonRpcResponse: string): string | null => {
|
|
128
|
+
let parsedResponse: {id: string, result?: SmoldotHealth, params?: { subscription: string }};
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
parsedResponse = JSON.parse(jsonRpcResponse) as { id: string, result?: SmoldotHealth };
|
|
132
|
+
} catch {
|
|
133
|
+
return jsonRpcResponse;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Check whether response is a response to `system_health`.
|
|
137
|
+
if (parsedResponse.id && this.#currentHealthCheckId === parsedResponse.id) {
|
|
138
|
+
this.#currentHealthCheckId = null;
|
|
139
|
+
|
|
140
|
+
// Check whether query was successful. It is possible for queries to fail for
|
|
141
|
+
// various reasons, such as the client being overloaded.
|
|
142
|
+
if (!parsedResponse.result) {
|
|
143
|
+
this.update(false);
|
|
144
|
+
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
this.#healthCallback(parsedResponse.result);
|
|
149
|
+
this.#isSyncing = parsedResponse.result.isSyncing;
|
|
150
|
+
this.update(false);
|
|
151
|
+
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Check whether response is a response to the subscription or unsubscription.
|
|
156
|
+
if (
|
|
157
|
+
parsedResponse.id &&
|
|
158
|
+
this.#currentSubunsubRequestId === parsedResponse.id
|
|
159
|
+
) {
|
|
160
|
+
this.#currentSubunsubRequestId = null;
|
|
161
|
+
|
|
162
|
+
// Check whether query was successful. It is possible for queries to fail for
|
|
163
|
+
// various reasons, such as the client being overloaded.
|
|
164
|
+
if (!parsedResponse.result) {
|
|
165
|
+
this.update(false);
|
|
166
|
+
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (this.#currentSubscriptionId) {
|
|
171
|
+
this.#currentSubscriptionId = null;
|
|
172
|
+
} else {
|
|
173
|
+
this.#currentSubscriptionId = parsedResponse.result as unknown as string;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
this.update(false);
|
|
177
|
+
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Check whether response is a notification to a subscription.
|
|
182
|
+
if (
|
|
183
|
+
parsedResponse.params &&
|
|
184
|
+
this.#currentSubscriptionId &&
|
|
185
|
+
parsedResponse.params.subscription === this.#currentSubscriptionId
|
|
186
|
+
) {
|
|
187
|
+
// Note that after a successful subscription, a notification containing
|
|
188
|
+
// the current best block is always returned. Considering that a
|
|
189
|
+
// subscription is performed in response to a health check, calling
|
|
190
|
+
// `startHealthCheck()` here will lead to a second health check.
|
|
191
|
+
// It might seem redundant to perform two health checks in a quick
|
|
192
|
+
// succession, but doing so doesn't lead to any problem, and it is
|
|
193
|
+
// actually possible for the health to have changed in between as the
|
|
194
|
+
// current best block might have been updated during the subscription
|
|
195
|
+
// request.
|
|
196
|
+
this.update(true);
|
|
197
|
+
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Response doesn't concern us.
|
|
202
|
+
if (parsedResponse.id) {
|
|
203
|
+
const id: string = parsedResponse.id;
|
|
204
|
+
|
|
205
|
+
// Need to remove the `extern:` prefix.
|
|
206
|
+
if (!id.startsWith('extern:')) {
|
|
207
|
+
throw new Error('State inconsistency in health checker');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const newId = JSON.parse(id.slice('extern:'.length)) as string;
|
|
211
|
+
|
|
212
|
+
parsedResponse.id = newId;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return stringify(parsedResponse);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
update = (startNow: boolean): void => {
|
|
219
|
+
// If `startNow`, clear `#currentHealthTimeout` so that it is set below.
|
|
220
|
+
if (startNow && this.#currentHealthTimeout) {
|
|
221
|
+
clearTimeout(this.#currentHealthTimeout);
|
|
222
|
+
this.#currentHealthTimeout = null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (!this.#currentHealthTimeout) {
|
|
226
|
+
const startHealthRequest = () => {
|
|
227
|
+
this.#currentHealthTimeout = null;
|
|
228
|
+
|
|
229
|
+
// No matter what, don't start a health request if there is already one in progress.
|
|
230
|
+
// This is sane to do because receiving a response to a health request calls `update()`.
|
|
231
|
+
if (this.#currentHealthCheckId) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Actual request starting.
|
|
236
|
+
this.#currentHealthCheckId = `health-checker:${this.#nextRequestId}`;
|
|
237
|
+
this.#nextRequestId += 1;
|
|
238
|
+
|
|
239
|
+
this.#requestToSmoldot({
|
|
240
|
+
id: this.#currentHealthCheckId,
|
|
241
|
+
jsonrpc: '2.0',
|
|
242
|
+
method: 'system_health',
|
|
243
|
+
params: []
|
|
244
|
+
});
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
if (startNow) {
|
|
248
|
+
startHealthRequest();
|
|
249
|
+
} else {
|
|
250
|
+
this.#currentHealthTimeout = setTimeout(startHealthRequest, 1000);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (
|
|
255
|
+
this.#isSyncing &&
|
|
256
|
+
!this.#currentSubscriptionId &&
|
|
257
|
+
!this.#currentSubunsubRequestId
|
|
258
|
+
) {
|
|
259
|
+
this.startSubscription();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (
|
|
263
|
+
!this.#isSyncing &&
|
|
264
|
+
this.#currentSubscriptionId &&
|
|
265
|
+
!this.#currentSubunsubRequestId
|
|
266
|
+
) {
|
|
267
|
+
this.endSubscription();
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
startSubscription = (): void => {
|
|
272
|
+
if (this.#currentSubunsubRequestId || this.#currentSubscriptionId) {
|
|
273
|
+
throw new Error('Internal error in health checker');
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
this.#currentSubunsubRequestId = `health-checker:${this.#nextRequestId}`;
|
|
277
|
+
this.#nextRequestId += 1;
|
|
278
|
+
|
|
279
|
+
this.#requestToSmoldot({
|
|
280
|
+
id: this.#currentSubunsubRequestId,
|
|
281
|
+
jsonrpc: '2.0',
|
|
282
|
+
method: 'chain_subscribeNewHeads',
|
|
283
|
+
params: []
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
endSubscription = (): void => {
|
|
288
|
+
if (this.#currentSubunsubRequestId || !this.#currentSubscriptionId) {
|
|
289
|
+
throw new Error('Internal error in health checker');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
this.#currentSubunsubRequestId = `health-checker:${this.#nextRequestId}`;
|
|
293
|
+
this.#nextRequestId += 1;
|
|
294
|
+
|
|
295
|
+
this.#requestToSmoldot({
|
|
296
|
+
id: this.#currentSubunsubRequestId,
|
|
297
|
+
jsonrpc: '2.0',
|
|
298
|
+
method: 'chain_unsubscribeNewHeads',
|
|
299
|
+
params: [this.#currentSubscriptionId]
|
|
300
|
+
});
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
destroy = (): void => {
|
|
304
|
+
if (this.#currentHealthTimeout) {
|
|
305
|
+
clearTimeout(this.#currentHealthTimeout);
|
|
306
|
+
this.#currentHealthTimeout = null;
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export class HealthCheckError extends Error {
|
|
312
|
+
readonly #cause: unknown;
|
|
313
|
+
|
|
314
|
+
getCause (): unknown {
|
|
315
|
+
return this.#cause;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
constructor (response: unknown, message = 'Got error response asking for system health') {
|
|
319
|
+
super(message);
|
|
320
|
+
|
|
321
|
+
this.#cause = response;
|
|
322
|
+
}
|
|
323
|
+
}
|