@dashevo/dapi-client 0.23.0-dev.9 → 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.
@@ -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-dev.9",
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": "~0.23.0-dev.9",
30
- "@dashevo/dash-spv": "~1.1.7-6",
31
- "@dashevo/dashcore-lib": "~0.19.41",
32
- "@dashevo/dpp": "~0.23.0-dev.9",
33
- "@dashevo/grpc-common": "~0.23.0-dev.9",
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.21.1",
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.3.4",
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",