@dashevo/dapi-client 0.23.0 → 0.23.1

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.
@@ -205,6 +205,10 @@ class BlockHeadersProvider extends EventEmitter {
205
205
  headersHandler(headersData, reject) {
206
206
  const { headers, headHeight } = headersData;
207
207
 
208
+ // TODO: simulate headers rejection and debug
209
+ // BlockHeadersReader might not correctly set startBlockHeight
210
+ // which results in orphan chunks in SPV
211
+
208
212
  try {
209
213
  const headersAdded = this.spvChain.addHeaders(headers, headHeight);
210
214
 
@@ -86,7 +86,7 @@ class BlockHeadersReader extends EventEmitter {
86
86
  stopReadingHistorical() {
87
87
  while (this.historicalStreams.length) {
88
88
  const stream = this.historicalStreams.shift();
89
- stream.cancel();
89
+ this.cancelStream(stream);
90
90
  }
91
91
  }
92
92
 
@@ -105,11 +105,20 @@ class BlockHeadersReader extends EventEmitter {
105
105
  throw new Error(`Invalid fromBlockHeight: ${fromBlockHeight}`);
106
106
  }
107
107
 
108
+ // We don't know yet whether we already have header at fromBlockHeight
108
109
  let lastKnownChainHeight = fromBlockHeight - 1;
109
110
 
110
111
  const stream = await this.createContinuousSyncStream(fromBlockHeight);
111
112
 
112
- stream.on('data', (data) => {
113
+ const errorHandler = (e) => {
114
+ this.continuousSyncStream = null;
115
+ if (e.code === GrpcErrorCodes.CANCELLED) {
116
+ return;
117
+ }
118
+ this.emit(EVENTS.ERROR, e);
119
+ };
120
+
121
+ const dataHandler = (data) => {
113
122
  const blockHeadersResponse = data.getBlockHeaders();
114
123
 
115
124
  if (blockHeadersResponse) {
@@ -125,35 +134,42 @@ class BlockHeadersReader extends EventEmitter {
125
134
  *
126
135
  * @param e
127
136
  */
128
- const rejectHeaders = (e) => {
129
- stream.destroy(e);
137
+ const rejectHeaders = async (e) => {
138
+ // Don't use cancelStream there because it's going to unsubscribe from events
139
+ stream.cancel();
140
+ stream.retryOnError(e);
130
141
  };
142
+
131
143
  this.emit(EVENTS.BLOCK_HEADERS, {
132
144
  headers,
133
145
  headHeight: batchHeadHeight,
134
146
  }, rejectHeaders);
135
147
  }
136
- });
148
+ };
137
149
 
138
- stream.on('beforeReconnect', (updateArguments) => {
150
+ const beforeReconnectHandler = (updateArguments) => {
139
151
  updateArguments({
140
152
  fromBlockHeight: lastKnownChainHeight,
153
+ count: 0,
141
154
  });
142
155
 
143
156
  lastKnownChainHeight -= 1;
144
- });
157
+ };
145
158
 
146
- stream.on('error', (e) => {
159
+ const endHandler = () => {
147
160
  this.continuousSyncStream = null;
148
- if (e.code === GrpcErrorCodes.CANCELLED) {
149
- return;
150
- }
151
- this.emit(EVENTS.ERROR, e);
152
- });
161
+ };
153
162
 
154
- stream.on('end', () => {
155
- this.continuousSyncStream = null;
156
- });
163
+ stream.on('data', dataHandler);
164
+ stream.on('beforeReconnect', beforeReconnectHandler);
165
+ stream.on('error', errorHandler);
166
+ stream.on('end', endHandler);
167
+
168
+ stream.removeAllListeners = () => {
169
+ stream.removeListener('data', dataHandler);
170
+ stream.removeListener('end', endHandler);
171
+ stream.removeListener('beforeReconnect', beforeReconnectHandler);
172
+ };
157
173
 
158
174
  this.continuousSyncStream = stream;
159
175
  return stream;
@@ -161,11 +177,13 @@ class BlockHeadersReader extends EventEmitter {
161
177
 
162
178
  unsubscribeFromNew() {
163
179
  if (this.continuousSyncStream) {
164
- this.continuousSyncStream.cancel();
180
+ this.cancelStream(this.continuousSyncStream);
165
181
  this.continuousSyncStream = null;
166
182
  }
167
183
  }
168
184
 
185
+ // TODO: refactor whole thing with ReconnectableStream that supports
186
+ // retry on error logic
169
187
  /**
170
188
  * A HOF that returns a function to subscribe to historical block headers and chain locks
171
189
  * and handles retry logic
@@ -189,37 +207,6 @@ class BlockHeadersReader extends EventEmitter {
189
207
 
190
208
  const stream = await this.createHistoricalSyncStream(fromBlockHeight, count);
191
209
 
192
- const dataHandler = (data) => {
193
- const blockHeaders = data.getBlockHeaders();
194
-
195
- if (blockHeaders) {
196
- const headersList = blockHeaders.getHeadersList()
197
- .map((header) => new BlockHeader(Buffer.from(header)));
198
-
199
- let rejected = false;
200
-
201
- /**
202
- * Kills stream in case of deliberate rejection from the outside
203
- *
204
- * @param e
205
- */
206
- const rejectHeaders = (e) => {
207
- rejected = true;
208
- stream.destroy(e);
209
- };
210
-
211
- const batchHeadHeight = fromBlockHeight + headersObtained;
212
- this.emit(EVENTS.BLOCK_HEADERS, {
213
- headers: headersList,
214
- headHeight: batchHeadHeight,
215
- }, rejectHeaders);
216
-
217
- if (!rejected) {
218
- headersObtained += headersList.length;
219
- }
220
- }
221
- };
222
-
223
210
  const errorHandler = (streamError) => {
224
211
  if (streamError.code === GrpcErrorCodes.CANCELLED) {
225
212
  // TODO: consider reworking with COMMANDS instead
@@ -251,6 +238,40 @@ class BlockHeadersReader extends EventEmitter {
251
238
  }
252
239
  };
253
240
 
241
+ const dataHandler = (data) => {
242
+ const blockHeaders = data.getBlockHeaders();
243
+
244
+ if (blockHeaders) {
245
+ const headersList = blockHeaders.getHeadersList()
246
+ .map((header) => new BlockHeader(Buffer.from(header)));
247
+
248
+ let rejected = false;
249
+
250
+ /**
251
+ * Kills stream in case of deliberate rejection from the outside
252
+ *
253
+ * @param e
254
+ */
255
+ const rejectHeaders = (e) => {
256
+ rejected = true;
257
+ // Cancel stream and unsubscribe from all data events
258
+ // because they are going th be re-created in errorHandler
259
+ this.cancelStream(stream);
260
+ errorHandler(e);
261
+ };
262
+
263
+ const batchHeadHeight = fromBlockHeight + headersObtained;
264
+ this.emit(EVENTS.BLOCK_HEADERS, {
265
+ headers: headersList,
266
+ headHeight: batchHeadHeight,
267
+ }, rejectHeaders);
268
+
269
+ if (!rejected) {
270
+ headersObtained += headersList.length;
271
+ }
272
+ }
273
+ };
274
+
254
275
  const endHandler = () => {
255
276
  const index = this.historicalStreams.indexOf(stream);
256
277
  this.historicalStreams.splice(index, 1);
@@ -267,11 +288,22 @@ class BlockHeadersReader extends EventEmitter {
267
288
  stream.on('error', errorHandler);
268
289
  stream.on('end', endHandler);
269
290
 
291
+ stream.removeAllListeners = () => {
292
+ stream.removeListener('data', dataHandler);
293
+ stream.removeListener('end', endHandler);
294
+ };
295
+
270
296
  return stream;
271
297
  };
272
298
 
273
299
  return subscribeWithRetries;
274
300
  }
301
+
302
+ // eslint-disable-next-line class-methods-use-this
303
+ cancelStream(stream) {
304
+ stream.removeAllListeners();
305
+ stream.cancel();
306
+ }
275
307
  }
276
308
 
277
309
  BlockHeadersReader.EVENTS = EVENTS;
package/lib/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ require('../polyfills/fetch-polyfill');
2
+
1
3
  const DAPIClient = require('./DAPIClient');
2
4
 
3
5
  const NotFoundError = require('./transport/GrpcTransport/errors/NotFoundError');
@@ -1,3 +1,5 @@
1
+ require('../../polyfills/fetch-polyfill');
2
+
1
3
  const { expect, use } = require('chai');
2
4
  const sinon = require('sinon');
3
5
  const sinonChai = require('sinon-chai');
@@ -7,20 +7,12 @@ class BlockHeadersWithChainLocksStreamMock extends EventEmitter {
7
7
  sinon.spy(this, 'on');
8
8
  sinon.spy(this, 'removeListener');
9
9
  sinon.spy(this, 'emit');
10
- sinon.spy(this, 'destroy');
11
10
  sinon.spy(this, 'removeAllListeners');
12
11
  sinon.spy(this, 'cancel');
13
12
 
14
13
  this.errored = false;
15
14
  }
16
15
 
17
- destroy(e) {
18
- this.emit('end');
19
- if (e) {
20
- this.emit('error', e);
21
- }
22
- }
23
-
24
16
  cancel() {
25
17
  if (!this.errored) {
26
18
  const err = new Error('CANCELED_ON_CLIENT');
@@ -48,6 +40,15 @@ class BlockHeadersWithChainLocksStreamMock extends EventEmitter {
48
40
  }),
49
41
  });
50
42
  }
43
+
44
+ errorHandler(e) {
45
+ this.emit('error', e);
46
+ }
47
+
48
+ end() {
49
+ this.emit('end');
50
+ this.removeAllListeners();
51
+ }
51
52
  }
52
53
 
53
54
  module.exports = BlockHeadersWithChainLocksStreamMock;
@@ -2,7 +2,7 @@ const cbor = require('cbor');
2
2
 
3
3
  const createConsensusError = require('@dashevo/dpp/lib/errors/consensus/createConsensusError');
4
4
  const GrpcErrorCodes = require('@dashevo/grpc-common/lib/server/error/GrpcErrorCodes');
5
- const { Metadata } = require('@grpc/grpc-js/build/src/metadata');
5
+ const { parseMetadata } = require('@dashevo/dapi-grpc');
6
6
 
7
7
  const NotFoundError = require('./errors/NotFoundError');
8
8
  const TimeoutError = require('./errors/TimeoutError');
@@ -50,15 +50,7 @@ function createGrpcTransportError(grpcError, dapiAddress) {
50
50
 
51
51
  const message = grpcError.details || grpcError.message;
52
52
 
53
- let metadata = {};
54
-
55
- if (grpcError.metadata) {
56
- // In cases of gRPC-Web client we get plain map instead of Metadata instance
57
- metadata = grpcError.metadata;
58
- if (grpcError.metadata instanceof Metadata) {
59
- metadata = grpcError.metadata.getMap();
60
- }
61
- }
53
+ const metadata = parseMetadata(grpcError.metadata) || {};
62
54
 
63
55
  // Error data
64
56
  const driveErrorData = metadata['drive-error-data-bin'];
@@ -1,5 +1,3 @@
1
- const axios = require('axios');
2
-
3
1
  const JsonRpcError = require('./errors/JsonRpcError');
4
2
  const WrongHttpCodeError = require('./errors/WrongHttpCodeError');
5
3
 
@@ -24,11 +22,6 @@ async function requestJsonRpc(host, port, method, params, options = {}) {
24
22
  id: 1,
25
23
  };
26
24
 
27
- const postOptions = {};
28
- if (options.timeout !== undefined) {
29
- postOptions.timeout = options.timeout;
30
- }
31
-
32
25
  const requestInfo = {
33
26
  host,
34
27
  port,
@@ -37,27 +30,32 @@ async function requestJsonRpc(host, port, method, params, options = {}) {
37
30
  options,
38
31
  };
39
32
 
40
- let response;
41
-
42
- try {
43
- response = await axios.post(
44
- url,
45
- payload,
46
- { timeout: options.timeout },
47
- );
48
- } catch (error) {
49
- if (error.response && error.response.status >= 500) {
50
- throw new WrongHttpCodeError(requestInfo, error.response.status, error.response.statusText);
51
- }
33
+ const requestOptions = {
34
+ method: 'POST',
35
+ body: JSON.stringify(payload),
36
+ headers: {
37
+ 'Content-Type': 'application/json',
38
+ },
39
+ };
52
40
 
53
- throw error;
41
+ let requestTimeoutId;
42
+ if (options.timeout) {
43
+ const controller = new AbortController();
44
+ requestTimeoutId = setTimeout(() => controller.abort(), options.timeout);
45
+ Object.assign(requestOptions, { signal: controller.signal });
54
46
  }
55
47
 
56
- if (response.status !== 200) {
57
- throw new WrongHttpCodeError(requestInfo, response.status, response.statusMessage);
48
+ // eslint-disable-next-line
49
+ const response = await fetch(url, requestOptions);
50
+
51
+ if (typeof requestTimeoutId !== 'undefined') {
52
+ clearTimeout(requestTimeoutId);
58
53
  }
54
+ const data = await response.json();
59
55
 
60
- const { data } = response;
56
+ if (!response.ok) {
57
+ throw new WrongHttpCodeError(requestInfo, response.status, response.statusText);
58
+ }
61
59
 
62
60
  if (data.error) {
63
61
  throw new JsonRpcError(requestInfo, data.error);
@@ -2,9 +2,18 @@ const EventEmitter = require('events');
2
2
  const GrpcErrorCodes = require('@dashevo/grpc-common/lib/server/error/GrpcErrorCodes');
3
3
  const wait = require('../utils/wait');
4
4
 
5
+ /**
6
+ * @typedef ReconnectableStreamOptions
7
+ * @property {number} [autoReconnectInterval]
8
+ * interval in MS to perform auto reconnect
9
+ * @property {number} [maxRetriesOnError]
10
+ * maximum amount of retry attempts on error happens. If set to -1, retries are infinite
11
+ * @property {number} [retryOnErrorDelay]
12
+ * delay in MS to perform retry after an error
13
+ */
5
14
  const defaultOptions = {
6
15
  // TODO: manage timeout according to the Nginx setting of the node
7
- reconnectTimeoutDelay: 50000,
16
+ autoReconnectInterval: 50000,
8
17
  maxRetriesOnError: 10,
9
18
  retryOnErrorDelay: 1000,
10
19
  };
@@ -17,69 +26,121 @@ const EVENTS = {
17
26
  };
18
27
 
19
28
  /**
20
- * Stream that provides auto-reconnect functionality
29
+ * A wrapper around grpc-js/grpc-web streams that provides auto-reconnect
30
+ * and retry on error functionality
31
+ * - Auto reconnect is needed to not hang on one node for too long.
32
+ * It happens within provided interval
33
+ * - Retry on error logic performs retry attempts until it reaches it's limit.
34
+ * After reaching limit, ReconnectableStream emits an error.
21
35
  */
22
36
  class ReconnectableStream extends EventEmitter {
23
- static create(fn, options) {
37
+ /**
38
+ * Helper that wraps stream creation function and performs auto connection
39
+ *
40
+ * @param {Function} createStreamFunction - function returning grpc-js/grpc-web stream
41
+ * @param {ReconnectableStreamOptions} options
42
+ * @returns {function(...[*]): Promise<ReconnectableStream>}
43
+ */
44
+ static create(createStreamFunction, options) {
24
45
  return async (...args) => {
25
- const reconnectableStream = new ReconnectableStream(fn, options);
46
+ const reconnectableStream = new ReconnectableStream(createStreamFunction, options);
26
47
  await reconnectableStream.connect(...args);
27
48
  return reconnectableStream;
28
49
  };
29
50
  }
30
51
 
31
- constructor(streamFunction, options = {}) {
52
+ /**
53
+ * @param {Function} createStream - function returning grpc-js/grpc-web stream
54
+ * @param {ReconnectableStreamOptions} options
55
+ */
56
+ constructor(createStream, options = {}) {
32
57
  super();
33
- this.stream = null;
34
- this.streamFunction = streamFunction;
35
- this.reconnectTimeout = null;
36
58
 
37
59
  const opts = { ...defaultOptions, ...options };
38
- this.reconnectTimeoutDelay = opts.reconnectTimeoutDelay;
39
- this.maxRetriesOnError = opts.maxRetriesOnError;
60
+
61
+ /**
62
+ * Auto-reconnect interval in millisecond
63
+ * It is needed to automatically reconnect to another DAPI node
64
+ *
65
+ * @type {number}
66
+ */
67
+ this.autoReconnectInterval = opts.autoReconnectInterval;
40
68
  this.retryOnErrorDelay = opts.retryOnErrorDelay;
41
- // Assign setTimeout and clearTimeout as class method for tests
42
- this.setTimeout = (callback, delay) => setTimeout(callback, delay);
43
69
 
44
- this.clearTimeout = (reference) => clearTimeout(reference);
70
+ /**
71
+ * Max amount of retries on error
72
+ */
73
+ this.maxRetriesOnError = opts.maxRetriesOnError;
45
74
 
46
75
  /**
47
- * Stream function arguments
76
+ * Current amount of retries on error
77
+ * (Does not have effect if maxRetriesOnError === -1)
78
+ */
79
+ this.retriesOnError = 0;
80
+
81
+ /**
82
+ * createStream arguments
48
83
  */
49
84
  this.args = null;
85
+ /**
86
+ * grpc stream
87
+ */
88
+ this.stream = null;
89
+
90
+ /**
91
+ * Function to wrap around to handle interval reconnects and error retries
92
+ */
93
+ this.createStream = createStream;
94
+
95
+ /**
96
+ * Reference to setTimeout managed by autoReconnectInterval
97
+ */
98
+ this.reconnectTimeout = null;
99
+
100
+ // For mocks
101
+ this.setTimeout = (callback, delay) => setTimeout(callback, delay);
102
+ this.clearTimeout = (reference) => clearTimeout(reference);
50
103
 
51
104
  this.connect = this.connect.bind(this);
52
105
  this.reconnect = this.reconnect.bind(this);
53
106
  this.cancel = this.cancel.bind(this);
54
- this.destroy = this.destroy.bind(this);
55
107
  this.errorHandler = this.errorHandler.bind(this);
56
108
  this.dataHandler = this.dataHandler.bind(this);
57
109
  this.endHandler = this.endHandler.bind(this);
58
110
  this.addListeners = this.addListeners.bind(this);
59
-
60
- // Manages retry attempts when error happens
61
- this.retriesOnError = 0;
62
111
  }
63
112
 
64
113
  async connect(...args) {
114
+ // Memorize current stream args (which can be altered by beforeReconnect logic)
65
115
  this.args = args;
66
- this.stream = await this.streamFunction(...this.args);
116
+
117
+ // Create grpc stream
118
+ this.stream = await this.createStream(...this.args);
119
+
120
+ // Add event listeners
67
121
  this.addListeners();
68
122
 
69
- if (this.reconnectTimeoutDelay > 0) {
70
- this.reconnectTimeout = this.setTimeout(
71
- this.reconnect,
72
- this.reconnectTimeoutDelay,
73
- );
123
+ if (this.autoReconnectInterval > 0) {
124
+ this.startAutoReconnect();
74
125
  }
75
126
  }
76
127
 
128
+ startAutoReconnect() {
129
+ if (this.reconnectTimeout) {
130
+ throw new Error('Auto reconnect timeout is already running.');
131
+ }
132
+ this.reconnectTimeout = this.setTimeout(
133
+ this.reconnect,
134
+ this.autoReconnectInterval,
135
+ );
136
+ }
137
+
77
138
  reconnect() {
78
139
  if (this.reconnectTimeout) {
79
140
  this.reconnectTimeout = null;
80
141
  this.stream.cancel();
81
142
 
82
- let newArgs = this.args;
143
+ let newArgs = this.args || [];
83
144
  const updateArgs = (...args) => {
84
145
  newArgs = args;
85
146
  };
@@ -91,6 +152,10 @@ class ReconnectableStream extends EventEmitter {
91
152
  }
92
153
 
93
154
  /**
155
+ * Function that adds EventEmitter style listeners
156
+ * to the stream and also rewires stream cancel function
157
+ * in order to automatically unsubscribe from events
158
+ *
94
159
  * @private
95
160
  */
96
161
  addListeners() {
@@ -100,6 +165,10 @@ class ReconnectableStream extends EventEmitter {
100
165
 
101
166
  const { cancel } = this.stream;
102
167
 
168
+ // Rewire cancel function in order to
169
+ // unsubscribe from DATA and END events.
170
+ // We don't unsubscribe from ERROR event because it
171
+ // handles `CANCELLED_ON_CLIENT` error after calling .cancel() and must stay
103
172
  this.stream.cancel = () => {
104
173
  this.stream.removeListener(EVENTS.DATA, this.dataHandler);
105
174
  this.stream.removeListener(EVENTS.END, this.endHandler);
@@ -107,72 +176,107 @@ class ReconnectableStream extends EventEmitter {
107
176
  };
108
177
  }
109
178
 
179
+ /**
180
+ * stream.on('data') handler
181
+ *
182
+ * @param data
183
+ */
110
184
  dataHandler(data) {
111
185
  this.emit(EVENTS.DATA, data);
112
186
  }
113
187
 
114
188
  /**
189
+ * stream.on('end') handler
190
+ *
115
191
  * @private
116
192
  */
117
193
  endHandler() {
118
- this.stopReconnectTimeout();
194
+ this.stopAutoReconnect();
119
195
  this.stream = null;
120
196
  this.emit(EVENTS.END);
121
197
  }
122
198
 
123
199
  /**
200
+ * stream.on('error') handler
201
+ *
124
202
  * @private
125
203
  * @param e
126
204
  */
127
205
  errorHandler(e) {
128
- this.stream.removeListener(EVENTS.ERROR, this.errorHandler);
206
+ // In case of cancellation nothing has to happen.
207
+ // TODO: do we need to propagate GrpcErrorCodes.CANCELLED further?
129
208
  if (e.code === GrpcErrorCodes.CANCELLED) {
130
209
  return;
131
210
  }
132
- this.stopReconnectTimeout();
133
211
 
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) => {
212
+ // Retry stream
213
+ this.retryOnError(e);
214
+ }
215
+
216
+ /**
217
+ * Manages retry logic
218
+ *
219
+ * @param e
220
+ */
221
+ retryOnError(e) {
222
+ // Stop reconnect timeout if there is one
223
+ this.stopAutoReconnect();
224
+
225
+ // Unsubscribe from events in case of the external call
226
+ this.stream.removeListener(EVENTS.END, this.endHandler);
227
+ this.stream.removeListener(EVENTS.DATA, this.dataHandler);
228
+
229
+ const canRetry = this.maxRetriesOnError === -1 // Infinite retries
230
+ || this.retriesOnError < this.maxRetriesOnError; // Or less than max limit
231
+
232
+ if (canRetry) {
233
+ // Handle 'beforeReconnect` logic
234
+ let newArgs = this.args || [];
235
+ const updateArgsBeforeReconnect = (...args) => {
140
236
  newArgs = args;
141
237
  };
142
238
 
143
- this.emit(EVENTS.BEFORE_RECONNECT, updateArgs);
239
+ // Emit beforeReconnect event in case parent would want to alter arguments
240
+ this.emit(EVENTS.BEFORE_RECONNECT, updateArgsBeforeReconnect);
144
241
 
242
+ // Wait before reconnecting
145
243
  wait(this.retryOnErrorDelay)
146
- .then(() => this.connect(...newArgs))
244
+ .then(() => this.connect(...newArgs))// Reconnect with new args
147
245
  .then(() => {
148
- this.retriesOnError += 1;
246
+ this.retriesOnError += 1; // Increase amount of current retries
149
247
  })
150
248
  .catch((connectError) => {
151
- this.emit(EVENTS.ERROR, connectError);
249
+ this.emit(EVENTS.ERROR, connectError); // Or emit error in case retry has failed
152
250
  });
153
251
  } else {
252
+ // Or simply emit error in case retry attempts were exhausted
154
253
  this.emit(EVENTS.ERROR, e);
155
254
  }
156
255
  }
157
256
 
158
257
  /**
258
+ * Stops auto reconnect timeout
259
+ *
159
260
  * @private
160
261
  */
161
- stopReconnectTimeout() {
262
+ stopAutoReconnect() {
162
263
  if (this.reconnectTimeout) {
163
264
  this.clearTimeout(this.reconnectTimeout);
164
265
  this.reconnectTimeout = null;
165
266
  }
166
267
  }
167
268
 
269
+ /**
270
+ * Cancels stream.
271
+ * Returns `stream.cancel()` to handle it from parent if needed.
272
+ * (grpc-js cancel() is asynchronous and grpc-web is synchronous)
273
+ *
274
+ * @returns {*}
275
+ */
168
276
  cancel() {
169
- this.stopReconnectTimeout();
277
+ this.stopAutoReconnect();
170
278
  return this.stream.cancel();
171
279
  }
172
-
173
- destroy(e) {
174
- this.stream.destroy(e);
175
- }
176
280
  }
177
281
 
178
282
  ReconnectableStream.EVENTS = EVENTS;
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.1",
4
4
  "description": "Client library used to access Dash DAPI endpoints",
5
5
  "main": "lib/index.js",
6
6
  "contributors": [
@@ -26,16 +26,15 @@
26
26
  }
27
27
  ],
28
28
  "dependencies": {
29
- "@dashevo/dapi-grpc": "0.23.0",
30
- "@dashevo/dash-spv": "0.23.0",
29
+ "@dashevo/dapi-grpc": "0.23.1",
30
+ "@dashevo/dash-spv": "0.23.1",
31
31
  "@dashevo/dashcore-lib": "~0.19.44",
32
- "@dashevo/dpp": "0.23.0",
33
- "@dashevo/grpc-common": "0.23.0",
34
- "@grpc/grpc-js": "^1.3.7",
35
- "axios": "^0.27.2",
32
+ "@dashevo/dpp": "0.23.1",
33
+ "@dashevo/grpc-common": "0.23.1",
36
34
  "bs58": "^4.0.1",
37
35
  "cbor": "^8.0.0",
38
36
  "lodash.sample": "^4.2.1",
37
+ "node-fetch": "^2.6.7",
39
38
  "node-inspect-extracted": "^1.0.8",
40
39
  "wasm-x11-hash": "~0.0.2"
41
40
  },