@dashevo/dapi-client 0.23.0-dev.8 → 0.23.0
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/README.md +5 -5
- package/lib/BlockHeadersProvider/BlockHeadersProvider.js +183 -50
- package/lib/BlockHeadersProvider/BlockHeadersReader.js +121 -71
- package/lib/BlockHeadersProvider/createBlockHeadersProviderFromOptions.js +31 -16
- package/lib/DAPIClient.js +0 -6
- package/lib/index.js +3 -0
- package/lib/networkConfigs.js +114 -150
- package/lib/test/bootstrap.js +6 -0
- package/lib/test/mocks/BlockHeadersWithChainLocksStreamMock.js +53 -0
- package/lib/test/mocks/mockHeadersChain.js +55 -0
- package/lib/transport/GrpcTransport/createGrpcTransportError.js +21 -26
- package/lib/transport/ReconnectableStream.js +180 -0
- package/lib/{test/utils → utils}/wait.js +0 -0
- package/package.json +10 -9
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
const EventEmitter = require('events');
|
|
2
|
+
const GrpcErrorCodes = require('@dashevo/grpc-common/lib/server/error/GrpcErrorCodes');
|
|
3
|
+
const wait = require('../utils/wait');
|
|
4
|
+
|
|
5
|
+
const defaultOptions = {
|
|
6
|
+
// TODO: manage timeout according to the Nginx setting of the node
|
|
7
|
+
reconnectTimeoutDelay: 50000,
|
|
8
|
+
maxRetriesOnError: 10,
|
|
9
|
+
retryOnErrorDelay: 1000,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const EVENTS = {
|
|
13
|
+
DATA: 'data',
|
|
14
|
+
ERROR: 'error',
|
|
15
|
+
END: 'end',
|
|
16
|
+
BEFORE_RECONNECT: 'beforeReconnect',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Stream that provides auto-reconnect functionality
|
|
21
|
+
*/
|
|
22
|
+
class ReconnectableStream extends EventEmitter {
|
|
23
|
+
static create(fn, options) {
|
|
24
|
+
return async (...args) => {
|
|
25
|
+
const reconnectableStream = new ReconnectableStream(fn, options);
|
|
26
|
+
await reconnectableStream.connect(...args);
|
|
27
|
+
return reconnectableStream;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
constructor(streamFunction, options = {}) {
|
|
32
|
+
super();
|
|
33
|
+
this.stream = null;
|
|
34
|
+
this.streamFunction = streamFunction;
|
|
35
|
+
this.reconnectTimeout = null;
|
|
36
|
+
|
|
37
|
+
const opts = { ...defaultOptions, ...options };
|
|
38
|
+
this.reconnectTimeoutDelay = opts.reconnectTimeoutDelay;
|
|
39
|
+
this.maxRetriesOnError = opts.maxRetriesOnError;
|
|
40
|
+
this.retryOnErrorDelay = opts.retryOnErrorDelay;
|
|
41
|
+
// Assign setTimeout and clearTimeout as class method for tests
|
|
42
|
+
this.setTimeout = (callback, delay) => setTimeout(callback, delay);
|
|
43
|
+
|
|
44
|
+
this.clearTimeout = (reference) => clearTimeout(reference);
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Stream function arguments
|
|
48
|
+
*/
|
|
49
|
+
this.args = null;
|
|
50
|
+
|
|
51
|
+
this.connect = this.connect.bind(this);
|
|
52
|
+
this.reconnect = this.reconnect.bind(this);
|
|
53
|
+
this.cancel = this.cancel.bind(this);
|
|
54
|
+
this.destroy = this.destroy.bind(this);
|
|
55
|
+
this.errorHandler = this.errorHandler.bind(this);
|
|
56
|
+
this.dataHandler = this.dataHandler.bind(this);
|
|
57
|
+
this.endHandler = this.endHandler.bind(this);
|
|
58
|
+
this.addListeners = this.addListeners.bind(this);
|
|
59
|
+
|
|
60
|
+
// Manages retry attempts when error happens
|
|
61
|
+
this.retriesOnError = 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async connect(...args) {
|
|
65
|
+
this.args = args;
|
|
66
|
+
this.stream = await this.streamFunction(...this.args);
|
|
67
|
+
this.addListeners();
|
|
68
|
+
|
|
69
|
+
if (this.reconnectTimeoutDelay > 0) {
|
|
70
|
+
this.reconnectTimeout = this.setTimeout(
|
|
71
|
+
this.reconnect,
|
|
72
|
+
this.reconnectTimeoutDelay,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
reconnect() {
|
|
78
|
+
if (this.reconnectTimeout) {
|
|
79
|
+
this.reconnectTimeout = null;
|
|
80
|
+
this.stream.cancel();
|
|
81
|
+
|
|
82
|
+
let newArgs = this.args;
|
|
83
|
+
const updateArgs = (...args) => {
|
|
84
|
+
newArgs = args;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
this.emit(EVENTS.BEFORE_RECONNECT, updateArgs);
|
|
88
|
+
this.connect(...newArgs)
|
|
89
|
+
.catch((connectError) => this.emit(EVENTS.ERROR, connectError));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @private
|
|
95
|
+
*/
|
|
96
|
+
addListeners() {
|
|
97
|
+
this.stream.on(EVENTS.DATA, this.dataHandler);
|
|
98
|
+
this.stream.on(EVENTS.ERROR, this.errorHandler);
|
|
99
|
+
this.stream.on(EVENTS.END, this.endHandler);
|
|
100
|
+
|
|
101
|
+
const { cancel } = this.stream;
|
|
102
|
+
|
|
103
|
+
this.stream.cancel = () => {
|
|
104
|
+
this.stream.removeListener(EVENTS.DATA, this.dataHandler);
|
|
105
|
+
this.stream.removeListener(EVENTS.END, this.endHandler);
|
|
106
|
+
cancel.call(this.stream);
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
dataHandler(data) {
|
|
111
|
+
this.emit(EVENTS.DATA, data);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @private
|
|
116
|
+
*/
|
|
117
|
+
endHandler() {
|
|
118
|
+
this.stopReconnectTimeout();
|
|
119
|
+
this.stream = null;
|
|
120
|
+
this.emit(EVENTS.END);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @private
|
|
125
|
+
* @param e
|
|
126
|
+
*/
|
|
127
|
+
errorHandler(e) {
|
|
128
|
+
this.stream.removeListener(EVENTS.ERROR, this.errorHandler);
|
|
129
|
+
if (e.code === GrpcErrorCodes.CANCELLED) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
this.stopReconnectTimeout();
|
|
133
|
+
|
|
134
|
+
if (
|
|
135
|
+
this.maxRetriesOnError === -1 // Infinite retries
|
|
136
|
+
|| this.retriesOnError < this.maxRetriesOnError // Limited retries
|
|
137
|
+
) {
|
|
138
|
+
let newArgs = this.args;
|
|
139
|
+
const updateArgs = (...args) => {
|
|
140
|
+
newArgs = args;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
this.emit(EVENTS.BEFORE_RECONNECT, updateArgs);
|
|
144
|
+
|
|
145
|
+
wait(this.retryOnErrorDelay)
|
|
146
|
+
.then(() => this.connect(...newArgs))
|
|
147
|
+
.then(() => {
|
|
148
|
+
this.retriesOnError += 1;
|
|
149
|
+
})
|
|
150
|
+
.catch((connectError) => {
|
|
151
|
+
this.emit(EVENTS.ERROR, connectError);
|
|
152
|
+
});
|
|
153
|
+
} else {
|
|
154
|
+
this.emit(EVENTS.ERROR, e);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @private
|
|
160
|
+
*/
|
|
161
|
+
stopReconnectTimeout() {
|
|
162
|
+
if (this.reconnectTimeout) {
|
|
163
|
+
this.clearTimeout(this.reconnectTimeout);
|
|
164
|
+
this.reconnectTimeout = null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
cancel() {
|
|
169
|
+
this.stopReconnectTimeout();
|
|
170
|
+
return this.stream.cancel();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
destroy(e) {
|
|
174
|
+
this.stream.destroy(e);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
ReconnectableStream.EVENTS = EVENTS;
|
|
179
|
+
|
|
180
|
+
module.exports = ReconnectableStream;
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dashevo/dapi-client",
|
|
3
|
-
"version": "0.23.0
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Client library used to access Dash DAPI endpoints",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"contributors": [
|
|
@@ -26,17 +26,18 @@
|
|
|
26
26
|
}
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@dashevo/dapi-grpc": "
|
|
30
|
-
"@dashevo/dash-spv": "
|
|
31
|
-
"@dashevo/dashcore-lib": "~0.19.
|
|
32
|
-
"@dashevo/dpp": "
|
|
33
|
-
"@dashevo/grpc-common": "
|
|
29
|
+
"@dashevo/dapi-grpc": "0.23.0",
|
|
30
|
+
"@dashevo/dash-spv": "0.23.0",
|
|
31
|
+
"@dashevo/dashcore-lib": "~0.19.44",
|
|
32
|
+
"@dashevo/dpp": "0.23.0",
|
|
33
|
+
"@dashevo/grpc-common": "0.23.0",
|
|
34
34
|
"@grpc/grpc-js": "^1.3.7",
|
|
35
|
-
"axios": "^0.
|
|
35
|
+
"axios": "^0.27.2",
|
|
36
36
|
"bs58": "^4.0.1",
|
|
37
37
|
"cbor": "^8.0.0",
|
|
38
38
|
"lodash.sample": "^4.2.1",
|
|
39
|
-
"node-inspect-extracted": "^1.0.8"
|
|
39
|
+
"node-inspect-extracted": "^1.0.8",
|
|
40
|
+
"wasm-x11-hash": "~0.0.2"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"@babel/core": "^7.15.5",
|
|
@@ -54,7 +55,7 @@
|
|
|
54
55
|
"eslint-plugin-import": "^2.24.2",
|
|
55
56
|
"eslint-plugin-jsdoc": "^27.0.0",
|
|
56
57
|
"events": "^3.3.0",
|
|
57
|
-
"karma": "^6.
|
|
58
|
+
"karma": "^6.4.1",
|
|
58
59
|
"karma-chai": "^0.1.0",
|
|
59
60
|
"karma-chrome-launcher": "^3.1.0",
|
|
60
61
|
"karma-firefox-launcher": "^2.1.1",
|