blind-peer 3.1.0 → 3.4.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.
Files changed (2) hide show
  1. package/index.js +196 -3
  2. package/package.json +6 -5
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,10 @@ 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
+ // Enable Small wants in Hypercore. Must be before anywhere that uses Hypercore
19
+ Hypercore.enable(Hypercore.SMALL_WANTS)
20
+
21
+ const { AddCoreEncoding, DeleteCoreEncoding } = require('blind-peer-encodings')
19
22
 
20
23
  class CoreTracker {
21
24
  constructor(blindPeer, core) {
@@ -228,7 +231,10 @@ class BlindPeer extends ReadyResource {
228
231
  bytesGcd: 0,
229
232
  coresAdded: 0,
230
233
  activations: 0,
231
- wakeups: 0
234
+ wakeups: 0,
235
+ addCoresRx: 0,
236
+ muxerPaired: 0,
237
+ muxerErrors: 0
232
238
  }
233
239
  }
234
240
 
@@ -426,6 +432,23 @@ class BlindPeer extends ReadyResource {
426
432
 
427
433
  rpc.respond('add-core', AddCoreEncoding, this._onaddcore.bind(this, conn))
428
434
  rpc.respond('delete-core', DeleteCoreEncoding, this._ondeletecore.bind(this, conn))
435
+
436
+ const self = this
437
+ BlindPeerMuxer.pair(conn, function () {
438
+ self.emit('muxer-paired', conn)
439
+ self.stats.muxerPaired++
440
+ new BlindPeerMuxer(conn, {
441
+ async oncores(request) {
442
+ try {
443
+ await self._onaddcores(conn, request)
444
+ } catch (e) {
445
+ self.stats.muxerErrors++
446
+ self.emit('muxer-error', e, conn)
447
+ throw e
448
+ }
449
+ }
450
+ })
451
+ })
429
452
  }
430
453
 
431
454
  async _activateCore(stream, record) {
@@ -497,6 +520,7 @@ class BlindPeer extends ReadyResource {
497
520
  const replicationLag = core.length - core.contiguousLength
498
521
  if (replicationLag > this.replicationLagThreshold || core.length === 0) {
499
522
  activeSession = this.swarm.join(core.discoveryKey, { server: true, client: true })
523
+ this.emit('core-client-mode-changed', core, true)
500
524
  } else {
501
525
  activeSession = this.swarm.join(core.discoveryKey, { server: true, client: false })
502
526
  }
@@ -549,6 +573,100 @@ class BlindPeer extends ReadyResource {
549
573
  return coreRecord
550
574
  }
551
575
 
576
+ async _onaddcores(stream, request) {
577
+ this.stats.addCoresRx++
578
+ const priority = Math.min(request.priority, 1) // 2 is reserved for trusted peers
579
+ const { cores, referrer } = request
580
+
581
+ if (request.announce !== false && !this._isTrustedPeer(stream.remotePublicKey)) {
582
+ // Note: we can't use the original downgrade-announce event because that assumes a 'record' object
583
+ this.emit('add-cores-downgrade-announce', {
584
+ request,
585
+ remotePublicKey: stream.remotePublicKey
586
+ })
587
+ request.announce = false
588
+ }
589
+
590
+ this.emit('add-cores-received', stream, request)
591
+
592
+ const discKeys = []
593
+ const overview = new Map()
594
+ for (const c of cores) {
595
+ const discoveryKey = crypto.discoveryKey(c.key)
596
+ discKeys.push(discoveryKey)
597
+ const id = IdEnc.normalize(discoveryKey)
598
+ overview.set(id, {
599
+ key: c.key,
600
+ discoveryKey,
601
+ remoteLength: c.length,
602
+ announce: request.announce,
603
+ priority,
604
+ referrer,
605
+ ownLength: 0, // set later
606
+ ownContigLength: 0, // set later
607
+ needsActivation: false // changed later if needed
608
+ })
609
+ }
610
+
611
+ const recordsToAdd = []
612
+ const infos = await this.store.storage.getInfos(discKeys)
613
+ for (let i = 0; i < infos.length; i++) {
614
+ const id = IdEnc.normalize(discKeys[i])
615
+ const storageInfo = infos[i]
616
+ const entry = overview.get(id)
617
+
618
+ // Note: just the null check does not suffice for storageInfo, because we already try
619
+ // loading some keys from other contexts, like when the system core of an autobase is
620
+ // used as a referrer.
621
+ if (
622
+ storageInfo === null ||
623
+ entry.announce ||
624
+ (storageInfo.head === null && entry.remoteLength > 0)
625
+ ) {
626
+ entry.needsActivation = true
627
+ recordsToAdd.push({
628
+ key: entry.key,
629
+ priority: entry.priority,
630
+ announce: entry.announce,
631
+ referrer: entry.referrer
632
+ })
633
+ } else {
634
+ entry.ownLength = storageInfo.head?.length || 0
635
+ entry.ownContigLength = storageInfo.hints?.contiguousLength || 0
636
+ if (entry.ownLength !== entry.remoteLength) entry.needsActivation = true
637
+ if (entry.ownLength > entry.ownContigLength) entry.needsActivation = true
638
+ }
639
+ }
640
+
641
+ // Note: not race condition safe when called with the same cores at a similar time,
642
+ // but it's no problem if we do add the same core twice
643
+ for (const record of recordsToAdd) this.db.addCore(record)
644
+ if (recordsToAdd.length > 0) await this.flush() // flush now as important data
645
+
646
+ if (referrer) {
647
+ const muxer = stream.userData
648
+ const core = this.store.get({ key: referrer })
649
+ await core.ready()
650
+ const discoveryKey = core.discoveryKey
651
+ await core.close()
652
+ await this._onwakeup(discoveryKey, muxer)
653
+ }
654
+
655
+ for (const r of recordsToAdd) this.emit('add-new-core', r, true, stream)
656
+
657
+ const activateProms = []
658
+ for (const entry of overview.values()) {
659
+ if (!entry.needsActivation) continue
660
+ this.stats.coresAdded++
661
+ this.emit('add-core', entry, true, stream)
662
+ activateProms.push(this._activateCore(stream, entry))
663
+ }
664
+ await Promise.all(activateProms)
665
+
666
+ this.emit('add-cores-done', stream, request)
667
+ return null
668
+ }
669
+
552
670
  async _ondeletecore(stream, { key }) {
553
671
  if (!this._isTrustedPeer(stream.remotePublicKey)) {
554
672
  this.emit('delete-blocked', stream, { key })
@@ -679,6 +797,81 @@ class BlindPeer extends ReadyResource {
679
797
  this.set(self.nrAnnouncedCores)
680
798
  }
681
799
  })
800
+
801
+ new promClient.Gauge({
802
+ // eslint-disable-line no-new
803
+ name: 'blind_peer_muxer_errors',
804
+ help: 'The amount of errors on the protomux muxer',
805
+ collect() {
806
+ this.set(self.stats.muxerErrors)
807
+ }
808
+ })
809
+ new promClient.Gauge({
810
+ // eslint-disable-line no-new
811
+ name: 'blind_peer_muxer_paired',
812
+ help: 'The amount of blind-peer-muxer sessions paired',
813
+ collect() {
814
+ this.set(self.stats.muxerPaired)
815
+ }
816
+ })
817
+ new promClient.Gauge({
818
+ // eslint-disable-line no-new
819
+ name: 'blind_peer_add_cores_rx',
820
+ help: 'The amount of add-cores requests received',
821
+ collect() {
822
+ this.set(self.stats.addCoresRx)
823
+ }
824
+ })
825
+ if (self.rocks.stats) {
826
+ new promClient.Gauge({
827
+ // eslint-disable-line no-new
828
+ name: 'blind_peer_rocks_gets',
829
+ help: 'The amount of get ops from RocksDB',
830
+ collect() {
831
+ this.set(self.rocks.stats.gets)
832
+ }
833
+ })
834
+ new promClient.Gauge({
835
+ // eslint-disable-line no-new
836
+ name: 'blind_peer_rocks_puts',
837
+ help: 'The amount of put ops to RocksDB',
838
+ collect() {
839
+ this.set(self.rocks.stats.puts)
840
+ }
841
+ })
842
+ new promClient.Gauge({
843
+ // eslint-disable-line no-new
844
+ name: 'blind_peer_rocks_deletes',
845
+ help: 'The amount of delete ops from RocksDB',
846
+ collect() {
847
+ this.set(self.rocks.stats.deletes)
848
+ }
849
+ })
850
+ new promClient.Gauge({
851
+ // eslint-disable-line no-new
852
+ name: 'blind_peer_rocks_range_deletes',
853
+ help: 'The amount of range delete ops from RocksDB',
854
+ collect() {
855
+ this.set(self.rocks.stats.rangeDeletes)
856
+ }
857
+ })
858
+ new promClient.Gauge({
859
+ // eslint-disable-line no-new
860
+ name: 'blind_peer_rocks_read_batches',
861
+ help: 'The amount of read batches from RocksDB',
862
+ collect() {
863
+ this.set(self.rocks.stats.readBatches)
864
+ }
865
+ })
866
+ new promClient.Gauge({
867
+ // eslint-disable-line no-new
868
+ name: 'blind_peer_rocks_write_batches',
869
+ help: 'The amount of write batches to RocksDB',
870
+ collect() {
871
+ this.set(self.rocks.stats.writeBatches)
872
+ }
873
+ })
874
+ }
682
875
  }
683
876
  }
684
877
 
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "blind-peer",
3
- "version": "3.1.0",
3
+ "version": "3.4.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.0",
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
- "hypercore": "^11.0.12",
13
+ "hypercore": "^11.26.0",
13
14
  "hypercore-crypto": "^3.5.0",
14
15
  "hypercore-id-encoding": "^1.3.0",
15
16
  "hyperdb": "^5.0.0",
@@ -26,13 +27,13 @@
26
27
  "devDependencies": {
27
28
  "bare-events": "^2.8.2",
28
29
  "bare-process": "^4.2.2",
29
- "blind-peering": "^1.13.0",
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
  },