blind-peer 3.0.1 → 3.2.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/index.js +168 -6
- package/package.json +5 -4
package/index.js
CHANGED
|
@@ -5,6 +5,7 @@ const ReadyResource = require('ready-resource')
|
|
|
5
5
|
const Hyperswarm = require('hyperswarm')
|
|
6
6
|
const ProtomuxRPC = require('protomux-rpc')
|
|
7
7
|
const c = require('compact-encoding')
|
|
8
|
+
const BlindPeerMuxer = require('blind-peer-muxer')
|
|
8
9
|
const b4a = require('b4a')
|
|
9
10
|
const crypto = require('hypercore-crypto')
|
|
10
11
|
const safetyCatch = require('safety-catch')
|
|
@@ -14,8 +15,7 @@ const IdEnc = require('hypercore-id-encoding')
|
|
|
14
15
|
|
|
15
16
|
const BlindPeerDB = require('./lib/db.js')
|
|
16
17
|
|
|
17
|
-
const { AddCoreEncoding } = require('blind-peer-encodings')
|
|
18
|
-
const { DeleteCoreEncoding } = require('blind-peer-encodings')
|
|
18
|
+
const { AddCoreEncoding, DeleteCoreEncoding } = require('blind-peer-encodings')
|
|
19
19
|
|
|
20
20
|
class CoreTracker {
|
|
21
21
|
constructor(blindPeer, core) {
|
|
@@ -196,7 +196,8 @@ class BlindPeer extends ReadyResource {
|
|
|
196
196
|
trustedPubKeys,
|
|
197
197
|
port,
|
|
198
198
|
announcingInterval = 100,
|
|
199
|
-
wakeupGcTickTime = null
|
|
199
|
+
wakeupGcTickTime = null,
|
|
200
|
+
replicationLagThreshold = 100
|
|
200
201
|
} = {}
|
|
201
202
|
) {
|
|
202
203
|
super()
|
|
@@ -221,12 +222,16 @@ class BlindPeer extends ReadyResource {
|
|
|
221
222
|
this.enableGc = enableGc
|
|
222
223
|
this.lock = new ScopeLock({ debounce: true })
|
|
223
224
|
this.announcedCores = new Map()
|
|
225
|
+
this.replicationLagThreshold = replicationLagThreshold
|
|
224
226
|
|
|
225
227
|
this.stats = {
|
|
226
228
|
bytesGcd: 0,
|
|
227
229
|
coresAdded: 0,
|
|
228
230
|
activations: 0,
|
|
229
|
-
wakeups: 0
|
|
231
|
+
wakeups: 0,
|
|
232
|
+
addCoresRx: 0,
|
|
233
|
+
muxerPaired: 0,
|
|
234
|
+
muxerErrors: 0
|
|
230
235
|
}
|
|
231
236
|
}
|
|
232
237
|
|
|
@@ -424,6 +429,23 @@ class BlindPeer extends ReadyResource {
|
|
|
424
429
|
|
|
425
430
|
rpc.respond('add-core', AddCoreEncoding, this._onaddcore.bind(this, conn))
|
|
426
431
|
rpc.respond('delete-core', DeleteCoreEncoding, this._ondeletecore.bind(this, conn))
|
|
432
|
+
|
|
433
|
+
const self = this
|
|
434
|
+
BlindPeerMuxer.pair(conn, function () {
|
|
435
|
+
self.emit('muxer-paired', conn)
|
|
436
|
+
self.stats.muxerPaired++
|
|
437
|
+
new BlindPeerMuxer(conn, {
|
|
438
|
+
async oncores(request) {
|
|
439
|
+
try {
|
|
440
|
+
await self._onaddcores(conn, request)
|
|
441
|
+
} catch (e) {
|
|
442
|
+
self.stats.muxerErrors++
|
|
443
|
+
self.emit('muxer-error', e, conn)
|
|
444
|
+
throw e
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
})
|
|
448
|
+
})
|
|
427
449
|
}
|
|
428
450
|
|
|
429
451
|
async _activateCore(stream, record) {
|
|
@@ -467,17 +489,38 @@ class BlindPeer extends ReadyResource {
|
|
|
467
489
|
const core = this.store.get({ key })
|
|
468
490
|
this.announcedCores.set(coreId, core)
|
|
469
491
|
|
|
492
|
+
let activeSession = null
|
|
493
|
+
|
|
470
494
|
core.on('append', () => {
|
|
495
|
+
const replicationLag = core.length - core.contiguousLength
|
|
496
|
+
if (!activeSession.isClient && replicationLag > this.replicationLagThreshold) {
|
|
497
|
+
activeSession.refresh({ server: true, client: true })
|
|
498
|
+
this.emit('core-client-mode-changed', core, true)
|
|
499
|
+
}
|
|
500
|
+
|
|
471
501
|
this.emit('core-append', core)
|
|
472
502
|
})
|
|
473
503
|
core.on('download', () => {
|
|
474
|
-
|
|
504
|
+
const replicationLag = core.length - core.contiguousLength
|
|
505
|
+
if (replicationLag === 0) {
|
|
506
|
+
if (activeSession.isClient) {
|
|
507
|
+
activeSession.refresh({ server: true, client: false })
|
|
508
|
+
this.emit('core-client-mode-changed', core, false)
|
|
509
|
+
}
|
|
510
|
+
|
|
475
511
|
this.emit('core-downloaded', core)
|
|
476
512
|
}
|
|
477
513
|
})
|
|
478
514
|
|
|
479
515
|
await core.ready()
|
|
480
|
-
|
|
516
|
+
|
|
517
|
+
const replicationLag = core.length - core.contiguousLength
|
|
518
|
+
if (replicationLag > this.replicationLagThreshold || core.length === 0) {
|
|
519
|
+
activeSession = this.swarm.join(core.discoveryKey, { server: true, client: true })
|
|
520
|
+
this.emit('core-client-mode-changed', core, true)
|
|
521
|
+
} else {
|
|
522
|
+
activeSession = this.swarm.join(core.discoveryKey, { server: true, client: false })
|
|
523
|
+
}
|
|
481
524
|
|
|
482
525
|
// WARNING: we do not yet handle the case where
|
|
483
526
|
// data of an announced core is cleared
|
|
@@ -527,6 +570,100 @@ class BlindPeer extends ReadyResource {
|
|
|
527
570
|
return coreRecord
|
|
528
571
|
}
|
|
529
572
|
|
|
573
|
+
async _onaddcores(stream, request) {
|
|
574
|
+
this.stats.addCoresRx++
|
|
575
|
+
const priority = Math.min(request.priority, 1) // 2 is reserved for trusted peers
|
|
576
|
+
const { cores, referrer } = request
|
|
577
|
+
|
|
578
|
+
if (request.announce !== false && !this._isTrustedPeer(stream.remotePublicKey)) {
|
|
579
|
+
// Note: we can't use the original downgrade-announce event because that assumes a 'record' object
|
|
580
|
+
this.emit('add-cores-downgrade-announce', {
|
|
581
|
+
request,
|
|
582
|
+
remotePublicKey: stream.remotePublicKey
|
|
583
|
+
})
|
|
584
|
+
request.announce = false
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
this.emit('add-cores-received', stream, request)
|
|
588
|
+
|
|
589
|
+
const discKeys = []
|
|
590
|
+
const overview = new Map()
|
|
591
|
+
for (const c of cores) {
|
|
592
|
+
const discoveryKey = crypto.discoveryKey(c.key)
|
|
593
|
+
discKeys.push(discoveryKey)
|
|
594
|
+
const id = IdEnc.normalize(discoveryKey)
|
|
595
|
+
overview.set(id, {
|
|
596
|
+
key: c.key,
|
|
597
|
+
discoveryKey,
|
|
598
|
+
remoteLength: c.length,
|
|
599
|
+
announce: request.announce,
|
|
600
|
+
priority,
|
|
601
|
+
referrer,
|
|
602
|
+
ownLength: 0, // set later
|
|
603
|
+
ownContigLength: 0, // set later
|
|
604
|
+
needsActivation: false // changed later if needed
|
|
605
|
+
})
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
const recordsToAdd = []
|
|
609
|
+
const infos = await this.store.storage.getInfos(discKeys)
|
|
610
|
+
for (let i = 0; i < infos.length; i++) {
|
|
611
|
+
const id = IdEnc.normalize(discKeys[i])
|
|
612
|
+
const storageInfo = infos[i]
|
|
613
|
+
const entry = overview.get(id)
|
|
614
|
+
|
|
615
|
+
// Note: just the null check does not suffice for storageInfo, because we already try
|
|
616
|
+
// loading some keys from other contexts, like when the system core of an autobase is
|
|
617
|
+
// used as a referrer.
|
|
618
|
+
if (
|
|
619
|
+
storageInfo === null ||
|
|
620
|
+
entry.announce ||
|
|
621
|
+
(storageInfo.head === null && entry.remoteLength > 0)
|
|
622
|
+
) {
|
|
623
|
+
entry.needsActivation = true
|
|
624
|
+
recordsToAdd.push({
|
|
625
|
+
key: entry.key,
|
|
626
|
+
priority: entry.priority,
|
|
627
|
+
announce: entry.announce,
|
|
628
|
+
referrer: entry.referrer
|
|
629
|
+
})
|
|
630
|
+
} else {
|
|
631
|
+
entry.ownLength = storageInfo.head?.length || 0
|
|
632
|
+
entry.ownContigLength = storageInfo.hints?.contiguousLength || 0
|
|
633
|
+
if (entry.ownLength !== entry.remoteLength) entry.needsActivation = true
|
|
634
|
+
if (entry.ownLength > entry.ownContigLength) entry.needsActivation = true
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// Note: not race condition safe when called with the same cores at a similar time,
|
|
639
|
+
// but it's no problem if we do add the same core twice
|
|
640
|
+
for (const record of recordsToAdd) this.db.addCore(record)
|
|
641
|
+
if (recordsToAdd.length > 0) await this.flush() // flush now as important data
|
|
642
|
+
|
|
643
|
+
if (referrer) {
|
|
644
|
+
const muxer = stream.userData
|
|
645
|
+
const core = this.store.get({ key: referrer })
|
|
646
|
+
await core.ready()
|
|
647
|
+
const discoveryKey = core.discoveryKey
|
|
648
|
+
await core.close()
|
|
649
|
+
await this._onwakeup(discoveryKey, muxer)
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
for (const r of recordsToAdd) this.emit('add-new-core', r, true, stream)
|
|
653
|
+
|
|
654
|
+
const activateProms = []
|
|
655
|
+
for (const entry of overview.values()) {
|
|
656
|
+
if (!entry.needsActivation) continue
|
|
657
|
+
this.stats.coresAdded++
|
|
658
|
+
this.emit('add-core', entry, true, stream)
|
|
659
|
+
activateProms.push(this._activateCore(stream, entry))
|
|
660
|
+
}
|
|
661
|
+
await Promise.all(activateProms)
|
|
662
|
+
|
|
663
|
+
this.emit('add-cores-done', stream, request)
|
|
664
|
+
return null
|
|
665
|
+
}
|
|
666
|
+
|
|
530
667
|
async _ondeletecore(stream, { key }) {
|
|
531
668
|
if (!this._isTrustedPeer(stream.remotePublicKey)) {
|
|
532
669
|
this.emit('delete-blocked', stream, { key })
|
|
@@ -657,6 +794,31 @@ class BlindPeer extends ReadyResource {
|
|
|
657
794
|
this.set(self.nrAnnouncedCores)
|
|
658
795
|
}
|
|
659
796
|
})
|
|
797
|
+
|
|
798
|
+
new promClient.Gauge({
|
|
799
|
+
// eslint-disable-line no-new
|
|
800
|
+
name: 'blind_peer_muxer_errors',
|
|
801
|
+
help: 'The amount of errors on the protomux muxer',
|
|
802
|
+
collect() {
|
|
803
|
+
this.set(self.stats.muxerErrors)
|
|
804
|
+
}
|
|
805
|
+
})
|
|
806
|
+
new promClient.Gauge({
|
|
807
|
+
// eslint-disable-line no-new
|
|
808
|
+
name: 'blind_peer_muxer_paired',
|
|
809
|
+
help: 'The amount of blind-peer-muxer sessions paired',
|
|
810
|
+
collect() {
|
|
811
|
+
this.set(self.stats.muxerPaired)
|
|
812
|
+
}
|
|
813
|
+
})
|
|
814
|
+
new promClient.Gauge({
|
|
815
|
+
// eslint-disable-line no-new
|
|
816
|
+
name: 'blind_peer_add_cores_rx',
|
|
817
|
+
help: 'The amount of add-cores requests received',
|
|
818
|
+
collect() {
|
|
819
|
+
this.set(self.stats.addCoresRx)
|
|
820
|
+
}
|
|
821
|
+
})
|
|
660
822
|
}
|
|
661
823
|
}
|
|
662
824
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blind-peer",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Blind peers help keep hypercores available",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"autobase": "^7.0.18",
|
|
8
8
|
"b4a": "^1.6.7",
|
|
9
|
-
"blind-peer-encodings": "^3.1.
|
|
9
|
+
"blind-peer-encodings": "^3.1.1",
|
|
10
|
+
"blind-peer-muxer": "^1.0.0",
|
|
10
11
|
"compact-encoding": "^2.16.0",
|
|
11
12
|
"corestore": "^7.4.4",
|
|
12
13
|
"hypercore": "^11.0.12",
|
|
@@ -26,13 +27,13 @@
|
|
|
26
27
|
"devDependencies": {
|
|
27
28
|
"bare-events": "^2.8.2",
|
|
28
29
|
"bare-process": "^4.2.2",
|
|
29
|
-
"
|
|
30
|
+
"bare-prom-client": "^15.1.3",
|
|
31
|
+
"blind-peering": "^2.0.0",
|
|
30
32
|
"brittle": "^3.7.0",
|
|
31
33
|
"debounceify": "^1.1.0",
|
|
32
34
|
"hyperdht": "^6.20.1",
|
|
33
35
|
"prettier": "^3.6.2",
|
|
34
36
|
"prettier-config-holepunch": "^2.0.0",
|
|
35
|
-
"bare-prom-client": "^15.1.3",
|
|
36
37
|
"test-tmp": "^1.3.0",
|
|
37
38
|
"which-runtime": "^1.3.2"
|
|
38
39
|
},
|