edge-currency-plugins 3.2.0 → 3.2.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.
@@ -176,25 +176,6 @@ var _constants = require('./constants');
176
176
  addresses: new Set(),
177
177
  blockHeight: 0
178
178
  })
179
- const setPickNextTaskCB = (
180
- callback
181
- ) => {
182
- pickNextTaskCB = callback
183
- }
184
-
185
- const stop = async () => {
186
- isEngineOn = false
187
- log(`stopping server states`)
188
- _socketQueue.removeIdFromQueue.call(void 0, walletInfo.id)
189
- clearTimeout(reconnectTimer)
190
- for (const uri of Object.keys(serverStatesCache)) {
191
- const serverState = serverStatesCache[uri]
192
- const { blockbook } = serverState
193
- if (blockbook == null) continue
194
- await blockbook.disconnect()
195
- _utils.removeItem.call(void 0, serverStatesCache, uri)
196
- }
197
- }
198
179
 
199
180
  const reconnect = () => {
200
181
  if (isEngineOn) {
@@ -202,22 +183,11 @@ var _constants = require('./constants');
202
183
  const reconnectionDelay = Math.max(5, reconnectCounter++) * 1000
203
184
  reconnectTimer = setTimeout(() => {
204
185
  clearTimeout(reconnectTimer)
205
- refillServers()
186
+ instance.refillServers()
206
187
  }, reconnectionDelay)
207
188
  }
208
189
  }
209
190
 
210
- const refillServers = () => {
211
- log(`refilling servers...`)
212
- isEngineOn = true
213
- _socketQueue.pushUpdate.call(void 0, {
214
- id: walletInfo.id,
215
- updateFunc: () => {
216
- doRefillServers()
217
- }
218
- })
219
- }
220
-
221
191
  const doRefillServers = () => {
222
192
  const includePatterns = ['wss:', 'ws:', 'electrumwss:', 'electrumws:']
223
193
  if (serverList.length === 0) {
@@ -338,240 +308,257 @@ var _constants = require('./constants');
338
308
  }
339
309
  }
340
310
 
341
- const serverCanGetTx = (uri, txid) => {
342
- const serverState = serverStatesCache[uri]
343
- if (serverState == null) return false
344
- if (serverState.txids.has(txid)) return true
311
+ const instance = {
312
+ async broadcastTx(transaction) {
313
+ return await new Promise((resolve, reject) => {
314
+ let resolved = false
315
+ let bad = 0
316
+
317
+ const wsUris = Object.keys(serverStatesCache).filter(
318
+ uri => serverStatesCache[uri].blockbook != null
319
+ )
320
+
321
+ // If there are no blockbook instances, reject the promise
322
+ if (wsUris.length < 1) {
323
+ reject(new Error('Unexpected error. Missing WebSocket connections.'))
324
+ // Exit early if there are blockbook instances
325
+ return
326
+ }
345
327
 
346
- for (const state of Object.values(serverStatesCache)) {
347
- if (state.txids.has(txid)) return false
348
- }
349
- return true
350
- }
328
+ // Determine if there are any connected blockbook instances
329
+ const isAnyBlockbookConnected = wsUris.some(
330
+ uri => serverStatesCache[uri].blockbook.isConnected
331
+ )
332
+
333
+ if (isAnyBlockbookConnected) {
334
+ for (const uri of wsUris) {
335
+ const { blockbook } = serverStatesCache[uri]
336
+ if (blockbook == null) continue
337
+ blockbook
338
+ .broadcastTx(transaction)
339
+ .then(response => {
340
+ if (!resolved) {
341
+ resolved = true
342
+ resolve(response.result)
343
+ }
344
+ })
345
+ .catch((e) => {
346
+ if (++bad === wsUris.length) {
347
+ const msg = e != null ? `With error ${e.message}` : ''
348
+ log.error(
349
+ `broadcastTx fail: ${JSON.stringify(transaction)}\n${msg}`
350
+ )
351
+ reject(e)
352
+ }
353
+ })
354
+ }
355
+ }
351
356
 
352
- const serverCanGetAddress = (uri, address) => {
353
- const serverState = serverStatesCache[uri]
354
- if (serverState == null) return false
355
- if (serverState.addresses.has(address)) return true
357
+ // Broadcast through any HTTP URI that may be configured, only if no
358
+ // blockbook instances are connected.
359
+ if (!isAnyBlockbookConnected) {
360
+ // This is for the future when we want to get HTTP servers from the user
361
+ // settings:
362
+ // const httpUris = pluginState.getLocalServers(Infinity, [
363
+ // /^http(?:s)?:/i
364
+ // ])
365
+
366
+ const { nowNodeApiKey } = initOptions
367
+ const nowNodeUris = serverConfigs
368
+ .filter(config => config.type === 'blockbook-nownode')
369
+ .map(config => config.uris)
370
+ .flat(1)
371
+
372
+ // If there are no HTTP servers, reject the promise
373
+ if (nowNodeUris.length < 1) {
374
+ // If no HTTP servers are available, and we had no connected blockbook
375
+ // instances, reject the promise with a message indicating no
376
+ // available connections. It's clear we have some connection instances
377
+ // if we gotten to this point, but we just don't have any of those
378
+ // instances connected at this time.
379
+ reject(
380
+ new Error('No available connections. Check your internet signal.')
381
+ )
382
+ return
383
+ }
384
+
385
+ // If there is no key for the NowNode servers:
386
+ if (nowNodeApiKey == null) {
387
+ reject(new Error('Missing connection key for fallback servers.'))
388
+ return
389
+ }
390
+
391
+ for (const uri of nowNodeUris) {
392
+ log.warn('Falling back to NOWNode server broadcast over HTTP:', uri)
393
+
394
+ // HTTP Fallback
395
+ io.fetchCors(`${uri}/api/v2/sendtx/`, {
396
+ method: 'POST',
397
+ headers: {
398
+ 'api-key': nowNodeApiKey
399
+ },
400
+ body: transaction.signedTx
401
+ })
402
+ .then(async response => {
403
+ if (!response.ok) {
404
+ throw new Error(
405
+ `Failed to broadcast transaction via Blockbook: HTTP ${response.status}`
406
+ )
407
+ }
408
+ const json = await response.json()
409
+ return _blockbookApi.asBlockbookResponse.call(void 0, (0, _blockbookApi.asBroadcastTxResponse))(json)
410
+ })
411
+ .then(response => {
412
+ if (!resolved) {
413
+ resolved = true
414
+ resolve(response.result)
415
+ }
416
+ })
417
+ .catch((e) => {
418
+ if (++bad === nowNodeUris.length) {
419
+ const msg = e != null ? `With error ${e.message}` : ''
420
+ log.error(
421
+ `broadcastTx fail: ${JSON.stringify(transaction)}\n${msg}`
422
+ )
423
+ reject(e)
424
+ }
425
+ })
426
+ }
427
+ }
428
+ })
429
+ },
356
430
 
357
- for (const state of Object.values(serverStatesCache)) {
358
- if (state.addresses.has(address)) return false
359
- }
360
- return true
361
- }
431
+ getBlockHeight(uri) {
432
+ return serverStatesCache[uri].blockHeight
433
+ },
362
434
 
363
- const serverIsAwareOfAddress = (uri, address) => {
364
- const serverState = serverStatesCache[uri]
365
- if (serverState == null) return false
366
- if (serverState.addresses.has(address)) return true
367
- return false
368
- }
435
+ getServerList() {
436
+ return serverList
437
+ },
369
438
 
370
- const getServerState = (uri) => {
371
- return serverStatesCache[uri]
372
- }
439
+ getServerState(uri) {
440
+ return serverStatesCache[uri]
441
+ },
373
442
 
374
- const getServerList = () => {
375
- return serverList
376
- }
443
+ refillServers() {
444
+ log(`refilling servers...`)
445
+ isEngineOn = true
446
+ _socketQueue.pushUpdate.call(void 0, {
447
+ id: walletInfo.id,
448
+ updateFunc: () => {
449
+ doRefillServers()
450
+ }
451
+ })
452
+ },
377
453
 
378
- const setServerList = (updatedServerList) => {
379
- serverList = updatedServerList
380
- }
454
+ setPickNextTaskCB(
455
+ callback
456
+ ) {
457
+ pickNextTaskCB = callback
458
+ },
381
459
 
382
- const broadcastTx = async (transaction) => {
383
- return await new Promise((resolve, reject) => {
384
- let resolved = false
385
- let bad = 0
460
+ setServerList(updatedServerList) {
461
+ serverList = updatedServerList
462
+ },
386
463
 
387
- const wsUris = Object.keys(serverStatesCache).filter(
388
- uri => serverStatesCache[uri].blockbook != null
389
- )
464
+ serverCanGetTx(uri, txid) {
465
+ const serverState = serverStatesCache[uri]
466
+ if (serverState == null) return false
467
+ if (serverState.txids.has(txid)) return true
390
468
 
391
- // If there are no blockbook instances, reject the promise
392
- if (wsUris.length < 1) {
393
- reject(new Error('Unexpected error. Missing WebSocket connections.'))
394
- // Exit early if there are blockbook instances
395
- return
469
+ for (const state of Object.values(serverStatesCache)) {
470
+ if (state.txids.has(txid)) return false
396
471
  }
472
+ return true
473
+ },
397
474
 
398
- // Determine if there are any connected blockbook instances
399
- const isAnyBlockbookConnected = wsUris.some(
400
- uri => serverStatesCache[uri].blockbook.isConnected
401
- )
475
+ serverCanGetAddress(uri, address) {
476
+ const serverState = serverStatesCache[uri]
477
+ if (serverState == null) return false
478
+ if (serverState.addresses.has(address)) return true
402
479
 
403
- if (isAnyBlockbookConnected) {
404
- for (const uri of wsUris) {
405
- const { blockbook } = serverStatesCache[uri]
406
- if (blockbook == null) continue
407
- blockbook
408
- .broadcastTx(transaction)
409
- .then(response => {
410
- if (!resolved) {
411
- resolved = true
412
- resolve(response.result)
413
- }
414
- })
415
- .catch((e) => {
416
- if (++bad === wsUris.length) {
417
- const msg = e != null ? `With error ${e.message}` : ''
418
- log.error(
419
- `broadcastTx fail: ${JSON.stringify(transaction)}\n${msg}`
420
- )
421
- reject(e)
422
- }
423
- })
424
- }
480
+ for (const state of Object.values(serverStatesCache)) {
481
+ if (state.addresses.has(address)) return false
425
482
  }
483
+ return true
484
+ },
426
485
 
427
- // Broadcast through any HTTP URI that may be configured, only if no
428
- // blockbook instances are connected.
429
- if (!isAnyBlockbookConnected) {
430
- // This is for the future when we want to get HTTP servers from the user
431
- // settings:
432
- // const httpUris = pluginState.getLocalServers(Infinity, [
433
- // /^http(?:s)?:/i
434
- // ])
435
-
436
- const { nowNodeApiKey } = initOptions
437
- const nowNodeUris = serverConfigs
438
- .filter(config => config.type === 'blockbook-nownode')
439
- .map(config => config.uris)
440
- .flat(1)
441
-
442
- // If there are no HTTP servers, reject the promise
443
- if (nowNodeUris.length < 1) {
444
- // If no HTTP servers are available, and we had no connected blockbook
445
- // instances, reject the promise with a message indicating no
446
- // available connections. It's clear we have some connection instances
447
- // if we gotten to this point, but we just don't have any of those
448
- // instances connected at this time.
449
- reject(
450
- new Error('No available connections. Check your internet signal.')
451
- )
452
- return
453
- }
454
-
455
- // If there is no key for the NowNode servers:
456
- if (nowNodeApiKey == null) {
457
- reject(new Error('Missing connection key for fallback servers.'))
458
- return
459
- }
486
+ serverIsAwareOfAddress(uri, address) {
487
+ const serverState = serverStatesCache[uri]
488
+ if (serverState == null) return false
489
+ if (serverState.addresses.has(address)) return true
490
+ return false
491
+ },
460
492
 
461
- for (const uri of nowNodeUris) {
462
- log.warn('Falling back to NOWNode server broadcast over HTTP:', uri)
463
-
464
- // HTTP Fallback
465
- io.fetchCors(`${uri}/api/v2/sendtx/`, {
466
- method: 'POST',
467
- headers: {
468
- 'api-key': nowNodeApiKey
469
- },
470
- body: transaction.signedTx
471
- })
472
- .then(async response => {
473
- if (!response.ok) {
474
- throw new Error(
475
- `Failed to broadcast transaction via Blockbook: HTTP ${response.status}`
476
- )
477
- }
478
- const json = await response.json()
479
- return _blockbookApi.asBlockbookResponse.call(void 0, (0, _blockbookApi.asBroadcastTxResponse))(json)
480
- })
481
- .then(response => {
482
- if (!resolved) {
483
- resolved = true
484
- resolve(response.result)
485
- }
486
- })
487
- .catch((e) => {
488
- if (++bad === nowNodeUris.length) {
489
- const msg = e != null ? `With error ${e.message}` : ''
490
- log.error(
491
- `broadcastTx fail: ${JSON.stringify(transaction)}\n${msg}`
492
- )
493
- reject(e)
494
- }
495
- })
496
- }
493
+ async stop() {
494
+ isEngineOn = false
495
+ log(`stopping server states`)
496
+ _socketQueue.removeIdFromQueue.call(void 0, walletInfo.id)
497
+ clearTimeout(reconnectTimer)
498
+ for (const uri of Object.keys(serverStatesCache)) {
499
+ const serverState = serverStatesCache[uri]
500
+ const { blockbook } = serverState
501
+ if (blockbook == null) continue
502
+ await blockbook.disconnect()
503
+ _utils.removeItem.call(void 0, serverStatesCache, uri)
497
504
  }
498
- })
499
- }
500
-
501
- const watchAddresses = (
502
- uri,
503
- addresses,
504
- deferredAddressSub
505
- ) => {
506
- const serverState = serverStatesCache[uri]
507
- if (serverState == null)
508
- throw new Error(`No blockbook connection with ${uri}`)
509
-
510
- const { blockbook } = serverState
505
+ },
511
506
 
512
- // Add new addresses to the set of known addresses
513
- for (const address of addresses) {
514
- serverState.addresses.add(address)
515
- }
507
+ watchAddresses(
508
+ uri,
509
+ addresses,
510
+ deferredAddressSub
511
+ ) {
512
+ const serverState = serverStatesCache[uri]
513
+ if (serverState == null)
514
+ throw new Error(`No blockbook connection with ${uri}`)
516
515
 
517
- const queryTime = Date.now()
518
- const deferred = new _Deferred2.default()
519
- deferred.promise
520
- .then((value) => {
521
- pluginState.serverScoreUp(uri, Date.now() - queryTime)
522
- _optionalChain([deferredAddressSub, 'optionalAccess', _ => _.resolve, 'call', _2 => _2(value)])
523
- })
524
- .catch(() => {
525
- // Remove new addresses to the set of known addresses
526
- for (const address of addresses) {
527
- serverState.addresses.delete(address)
528
- }
529
- pluginState.serverScoreDown(uri)
530
- _optionalChain([deferredAddressSub, 'optionalAccess', _3 => _3.reject, 'call', _4 => _4()])
531
- })
532
- blockbook.watchAddresses(Array.from(serverState.addresses), deferred)
533
- }
516
+ const { blockbook } = serverState
534
517
 
535
- const watchBlocks = (uri) => {
536
- const serverState = serverStatesCache[uri]
537
- if (serverState == null)
538
- throw new Error(`No blockbook connection with ${uri}`)
518
+ // Add new addresses to the set of known addresses
519
+ for (const address of addresses) {
520
+ serverState.addresses.add(address)
521
+ }
539
522
 
540
- const { blockbook } = serverState
523
+ const queryTime = Date.now()
524
+ const deferred = new _Deferred2.default()
525
+ deferred.promise
526
+ .then((value) => {
527
+ pluginState.serverScoreUp(uri, Date.now() - queryTime)
528
+ _optionalChain([deferredAddressSub, 'optionalAccess', _ => _.resolve, 'call', _2 => _2(value)])
529
+ })
530
+ .catch(() => {
531
+ // Remove new addresses to the set of known addresses
532
+ for (const address of addresses) {
533
+ serverState.addresses.delete(address)
534
+ }
535
+ pluginState.serverScoreDown(uri)
536
+ _optionalChain([deferredAddressSub, 'optionalAccess', _3 => _3.reject, 'call', _4 => _4()])
537
+ })
538
+ blockbook.watchAddresses(Array.from(serverState.addresses), deferred)
539
+ },
541
540
 
542
- serverState.blockSubscriptionStatus = 'subscribing'
541
+ watchBlocks(uri) {
542
+ const serverState = serverStatesCache[uri]
543
+ if (serverState == null)
544
+ throw new Error(`No blockbook connection with ${uri}`)
543
545
 
544
- const queryTime = Date.now()
545
- const deferred = new (0, _Deferred2.default)()
546
- deferred.promise
547
- .then(() => {
548
- serverState.blockSubscriptionStatus = 'subscribed'
549
- pluginState.serverScoreUp(uri, Date.now() - queryTime)
550
- })
551
- .catch(() => {
552
- serverState.blockSubscriptionStatus = 'unsubscribed'
553
- })
554
- blockbook.watchBlocks(deferred)
555
- }
546
+ const { blockbook } = serverState
556
547
 
557
- const getBlockHeight = (uri) => {
558
- return serverStatesCache[uri].blockHeight
559
- }
548
+ serverState.blockSubscriptionStatus = 'subscribing'
560
549
 
561
- const instance = {
562
- setPickNextTaskCB,
563
- stop,
564
- serverCanGetTx,
565
- serverCanGetAddress,
566
- serverIsAwareOfAddress,
567
- getServerState,
568
- refillServers,
569
- getServerList,
570
- setServerList,
571
- broadcastTx,
572
- watchAddresses,
573
- watchBlocks,
574
- getBlockHeight,
550
+ const queryTime = Date.now()
551
+ const deferred = new (0, _Deferred2.default)()
552
+ deferred.promise
553
+ .then(() => {
554
+ serverState.blockSubscriptionStatus = 'subscribed'
555
+ pluginState.serverScoreUp(uri, Date.now() - queryTime)
556
+ })
557
+ .catch(() => {
558
+ serverState.blockSubscriptionStatus = 'unsubscribed'
559
+ })
560
+ blockbook.watchBlocks(deferred)
561
+ },
575
562
 
576
563
  //
577
564
  // Task Methods:
@@ -126,11 +126,11 @@ const asResponseDefault = (raw) => [
126
126
  let connected = false
127
127
  let cancelConnect = false
128
128
  const timeout = 1000 * (_nullishCoalesce(config.timeout, () => ( 30)))
129
- let error
129
+ let trackedError
130
130
  let timer
131
131
 
132
132
  const handleError = (e) => {
133
- if (error == null) error = e
133
+ if (trackedError == null) trackedError = e
134
134
  if (connected && socket != null && socket.readyState === _types3.ReadyState.OPEN)
135
135
  disconnect()
136
136
  else cancelConnect = true
@@ -146,22 +146,28 @@ const asResponseDefault = (raw) => [
146
146
  }
147
147
 
148
148
  const onSocketClose = () => {
149
- const err = _nullishCoalesce(error, () => ( new Error('Socket close')))
150
- log.warn(`onSocketClose due to ${err.message} with server ${uri}`)
149
+ const errObj =
150
+ trackedError != null
151
+ ? trackedError instanceof Error
152
+ ? trackedError
153
+ : new Error(String(trackedError))
154
+ : new Error('Socket closed without error')
155
+ log.warn(`onSocketClose with server ${uri}: ${errObj.message}`)
151
156
  clearTimeout(timer)
152
157
  connected = false
153
158
  socket = null
154
159
  cancelConnect = false
160
+ trackedError = undefined
155
161
  for (const request of Object.values(pendingRequests)) {
156
162
  try {
157
- request.task.deferred.reject(err)
163
+ request.task.deferred.reject(errObj)
158
164
  } catch (e) {
159
165
  log.error(e.message)
160
166
  }
161
167
  }
162
168
  pendingRequests = {}
163
169
  try {
164
- emitter.emit(_SocketEmitter.SocketEvent.CONNECTION_CLOSE, uri, err)
170
+ emitter.emit(_SocketEmitter.SocketEvent.CONNECTION_CLOSE, uri, errObj)
165
171
  } catch (e) {
166
172
  log.error(e.message)
167
173
  }
@@ -267,7 +273,7 @@ const asResponseDefault = (raw) => [
267
273
  .then(() => {
268
274
  emitter.emit(_SocketEmitter.SocketEvent.CONNECTION_TIMER, uri, now)
269
275
  })
270
- .catch((e) => handleError(e))
276
+ .catch(e => handleError(e))
271
277
  }
272
278
 
273
279
  for (const [id, request] of Object.entries(pendingRequests)) {
@@ -384,8 +390,8 @@ const asResponseDefault = (raw) => [
384
390
  resolve()
385
391
  },
386
392
  onMessage: onMessage,
387
- onError: event => {
388
- error = new Error(JSON.stringify(event))
393
+ onError: err => {
394
+ trackedError = new Error(String(err))
389
395
  },
390
396
  onClose: onSocketClose
391
397
  }
@@ -14,8 +14,8 @@
14
14
  socket.onmessage = (message) => {
15
15
  callbacks.onMessage(message.data.toString())
16
16
  }
17
- socket.onerror = () => {
18
- callbacks.onError()
17
+ socket.onerror = event => {
18
+ callbacks.onError(event)
19
19
  }
20
20
  socket.onclose = () => {
21
21
  callbacks.onClose()
@@ -27,7 +27,7 @@ export interface PluginState {
27
27
  serverScoreUp: (uri: string, score: number) => void;
28
28
  clearCache: () => Promise<void>;
29
29
  getLocalServers: (numServersWanted: number, includePatterns?: Array<string | RegExp>) => string[];
30
- refreshServers: () => Promise<void>;
30
+ refreshServers: (updatedCustomServers?: string[]) => Promise<void>;
31
31
  updateServers: (settings: UtxoUserSettings) => Promise<void>;
32
32
  }
33
33
  export declare function makePluginState(settings: PluginStateSettings): PluginState;
@@ -25,6 +25,7 @@ export declare const asServerCache: import("cleaners").ObjectCleaner<{
25
25
  numResponseTimes: any;
26
26
  };
27
27
  };
28
+ enableCustomServers: boolean;
28
29
  internalServers: {
29
30
  [keys: string]: {
30
31
  serverUrl: any;
@@ -1,5 +1,5 @@
1
1
  export interface InnerSocketCallbacks {
2
- onError: (error?: Error) => void;
2
+ onError: (error?: unknown) => void;
3
3
  onMessage: (message: string) => void;
4
4
  onClose: (error?: Error) => void;
5
5
  onOpen: () => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "edge-currency-plugins",
3
- "version": "3.2.0",
3
+ "version": "3.2.1",
4
4
  "description": "Edge currency plugins to fetch and process wallet accounts, balances and transactions.",
5
5
  "homepage": "https://edge.app/",
6
6
  "repository": "https://github.com/EdgeApp/edge-currency-plugins",