blind-peer 0.0.3 → 2.7.4

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/README.md CHANGED
@@ -1,13 +1,81 @@
1
1
  # blind-peer
2
2
 
3
- Its a blind peer
3
+ Blind peers help keep hypercores available.
4
+
5
+ ## Installation
6
+
7
+ Install globally to use the `blind-peer` command:
4
8
 
5
9
  ```
6
- npm install blind-peer
10
+ npm install -g blind-peer
7
11
  ```
8
12
 
9
13
  ## Usage
10
14
 
15
+ Run a blind peer:
16
+
17
+ ```
18
+ blind-peer
19
+ ```
20
+
21
+ ### Command Line Options
22
+
23
+ - `--storage|-s [path]` - Storage path, defaults to ./blind-peer
24
+ - `--port|-p [int]` - DHT Port to try to bind to. Only relevant when that port is not firewalled. (defaults to a random port)
25
+ - `--trusted-peer|-t [trusted-peer]` - Public key of a trusted peer (allowed to set announce: true). Can be specified multiple times.
26
+ - `--debug|-d` - Enable debug mode (more logs). Can be specified multiple times.
27
+ - `--max-storage|-m [int]` - Max storage usage, in Mb (defaults to 100000)
28
+ - `--autodiscovery-rpc-key [autodiscovery-rpc-key]` - Public key where the autodiscovery service is listening. When set, the autodiscovery-seed must also be set. Can be hex or z32.
29
+ - `--autodiscovery-seed [autodiscovery-seed]` - 64-byte seed used to authenticate to the autodiscovery service. Can be hex or z32.
30
+ - `--autodiscovery-service-name [autodiscovery-service-name]` - Name under which to register the service (default blind-peer)
31
+ - `--scraper-public-key [scraper-public-key]` - Public key of a dht-prometheus scraper. Can be hex or z32.
32
+ - `--scraper-secret [scraper-secret]` - Secret of the dht-prometheus scraper. Can be hex or z32.
33
+ - `--scraper-alias [scraper-alias]` - (optional) Alias with which to register to the scraper
34
+
35
+ ### Output
36
+
37
+ When started, ndjson (pino) will be emitted for events. An example startup will look like:
38
+
39
+ ```
40
+ {"level":30,"time":1751662694931,"pid":96069,"hostname":"L293","msg":"Starting blind peer"}
41
+ {"level":30,"time":1751662694932,"pid":96069,"hostname":"L293","msg":"Using storage 'blind-peer'"}
42
+ {"level":30,"time":1751662696936,"pid":96069,"hostname":"L293","msg":"Blind peer listening, local address is 10.0.0.214:49741"}
43
+ {"level":30,"time":1751662696936,"pid":96069,"hostname":"L293","msg":"Bytes allocated: 0B of 100GB"}
44
+ {"level":30,"time":1751662696936,"pid":96069,"hostname":"L293","msg":"Listening at es4n7ty45odd1udfqyi9xz58mrbheuhdnxgdufsn9gz6e5uhsqco"}
45
+ {"level":30,"time":1751662696936,"pid":96069,"hostname":"L293","msg":"Encryption public key is ur7d9r7s3zf1ryibixt5139bep67y94s5bg4gckzo1p6qgtwwfyy"}
46
+ ```
47
+
48
+ ### Using a Blind Peer
49
+
50
+ To use a blind peer, use [blind-peering](https://github.com/holepunchto/blind-peering)
51
+
52
+ Here is an example, using the key from above
53
+
54
+ ```
55
+ import BlindPeering from '@holepunchto/blind-peering'
56
+ import Hyperswarm from 'hyperswarm'
57
+ import Corestore from 'corestore'
58
+ import Wakeup from 'protomux-wakeup'
59
+
60
+ const store = new Corestore(Pear.config.storage)
61
+ const swarm = new Hyperswarm()
62
+ const wakeup = new Wakeup()
63
+
64
+ const DEFAULT_BLIND_PEER_KEYS = ['es4n7ty45odd1udfqyi9xz58mrbheuhdnxgdufsn9gz6e5uhsqco']
65
+ const blind = new BlindPeering(swarm, store, { wakeup, mirrors: DEFAULT_BLIND_PEER_KEYS })
66
+ blind.addAutobaseBackground(autobase1)
67
+ blind.addCore(core1, autobase1.wakeupCapability.key)
68
+
69
+ ```
70
+
71
+ Related services:
72
+
73
+ https://github.com/holepunchto/autobase-discovery
74
+ https://github.com/HDegroote/dht-prometheus
75
+
76
+
77
+ ## Programmatic Usage
78
+
11
79
  ``` js
12
80
  const BlindPeer = require('blind-peer')
13
81
  ```
package/bin.js CHANGED
@@ -3,27 +3,186 @@
3
3
  const { command, flag } = require('paparam')
4
4
  const goodbye = require('graceful-goodbye')
5
5
  const idEnc = require('hypercore-id-encoding')
6
+ const Instrumentation = require('hyper-instrument')
7
+ const RegisterClient = require('autobase-discovery/client/register')
8
+ const safetyCatch = require('safety-catch')
9
+ const byteSize = require('tiny-byte-size')
10
+ const pino = require('pino')
11
+
6
12
  const BlindPeer = require('.')
7
13
 
14
+ const SERVICE_NAME = 'blind-peer'
15
+ const DEFAULT_STORAGE_LIMIT_MB = 100_000
16
+
8
17
  const cmd = command('blind-peer',
9
- flag('--storage|-s [path]', 'storage path, defaults to ./blind-peer'),
18
+ flag('--storage|-s [path]', 'Storage path, defaults to ./blind-peer'),
19
+ flag('--port|-p [int]', 'DHT Port to try to bind to. Only relevant when that port is not firewalled. (defaults to a random port)'),
20
+ flag('--trusted-peer|-t [trusted-peer]', 'Public key of a trusted peer (allowed to set announce: true). Can be more than 1.').multiple(),
21
+ flag('--debug|-d', 'Enable debug mode (more logs)').multiple(),
22
+ flag(`--max-storage|-m [int]', 'Max storage usage, in Mb (defaults to ${DEFAULT_STORAGE_LIMIT_MB})`),
23
+ flag('--autodiscovery-rpc-key [autodiscovery-rpc-key]', 'Public key where the autodiscovery service is listening. When set, the autodiscovery-seed must also be set. Can be hex or z32.'),
24
+ flag('--autodiscovery-seed [autodiscovery-seed]', '64-byte seed used to authenticate to the autodiscovery service. Can be hex or z32.'),
25
+ flag('--autodiscovery-service-name [autodiscovery-service-name]', `Name under which to register the service (default ${SERVICE_NAME})`),
26
+ flag('--scraper-public-key [scraper-public-key]', 'Public key of a dht-prometheus scraper. Can be hex or z32.'),
27
+ flag('--scraper-secret [scraper-secret]', 'Secret of the dht-prometheus scraper. Can be hex or z32.'),
28
+ flag('--scraper-alias [scraper-alias]', '(optional) Alias with which to register to the scraper'),
29
+ flag('--repl', 'Expose a repl-swarm (use for debugging only)'),
10
30
  async function ({ flags }) {
11
- console.info('Starting blind peer')
31
+ const debug = flags.debug
32
+ const logger = pino({
33
+ level: debug ? 'debug' : 'info'
34
+ })
35
+ logger.info('Starting blind peer')
12
36
 
13
37
  const storage = flags.storage || 'blind-peer'
14
- const blindPeer = new BlindPeer(storage)
38
+ const port = flags.port ? parseInt(flags.port) : null
39
+
40
+ const exposeRepl = flags.repl === true
41
+ const maxBytes = 1_000_000 * parseInt(flags.maxStorage || DEFAULT_STORAGE_LIMIT_MB)
42
+ const trustedPubKeys = (flags.trustedPeer || []).map(k => idEnc.decode(k))
43
+
44
+ const blindPeer = new BlindPeer(storage, { trustedPubKeys, maxBytes, port })
45
+
46
+ blindPeer.on('post-to-mailbox', req => {
47
+ try {
48
+ logger.info(`post-to-mailbox request received for mailbox: ${idEnc.normalize(req.mailbox)} with message ${idEnc.normalize(req.message)})`)
49
+ } catch {
50
+ logger.info('Invalid post-to-mailbox request received')
51
+ logger.info(req)
52
+ }
53
+ })
54
+
55
+ blindPeer.on('add-core', record => {
56
+ try {
57
+ logger.info(`add-core request received for record ${recordToStr(record)}`)
58
+ } catch (e) {
59
+ logger.info(`Invalid add-core request received: ${e.stack}`)
60
+ logger.info(record)
61
+ }
62
+ })
63
+
64
+ blindPeer.on('downgrade-announce', ({ record, remotePublicKey }) => {
65
+ try {
66
+ logger.info(`Downgraded announce for peer ${idEnc.normalize(remotePublicKey)} because the peer is not trusted (Original: ${recordToStr(record)})`)
67
+ } catch (e) {
68
+ logger.error(`Unexpected error while logging downgrade-announce: ${e.stack}`)
69
+ }
70
+ })
71
+
72
+ blindPeer.on('announce-core', core => {
73
+ logger.info(`Started announcing core ${coreToInfo(core)}`)
74
+ })
75
+ blindPeer.on('core-downloaded', core => {
76
+ logger.info(`Announced core fully downloaded: ${coreToInfo(core)}`)
77
+ })
78
+ blindPeer.on('core-append', core => {
79
+ logger.info(`Detected announced-core length update: ${coreToInfo(core)}`)
80
+ })
15
81
 
16
- console.info(`Using storage '${storage}'`)
82
+ blindPeer.on('gc-start', ({ bytesToClear }) => {
83
+ logger.info(`Starting GC, trying to clear ${byteSize(bytesToClear)} (bytes allocated: ${byteSize(blindPeer.digest.bytesAllocated)} of ${byteSize(blindPeer.maxBytes)})`)
84
+ })
85
+ blindPeer.on('gc-done', ({ bytesCleared }) => {
86
+ logger.info(`Completed GC, cleared ${byteSize(bytesCleared)} bytes (bytes allocated: ${byteSize(blindPeer.digest.bytesAllocated)} of ${byteSize(blindPeer.maxBytes)})`)
87
+ })
88
+ if (debug) {
89
+ blindPeer.on('core-activity', (core) => {
90
+ logger.debug(`Core activity for ${coreToInfo(core)}`)
91
+ })
92
+ }
17
93
 
94
+ logger.info(`Using storage '${storage}'`)
95
+ if (trustedPubKeys.length > 0) {
96
+ logger.info(`Trusted public keys:\n -${[...blindPeer.trustedPubKeys].map(idEnc.normalize).join('\n -')}`)
97
+ }
98
+
99
+ let instrumentation = null
18
100
  goodbye(async () => {
19
- console.info('Shutting down blind peer')
101
+ if (instrumentation) {
102
+ logger.info('Closing instrumentation')
103
+ await instrumentation.close()
104
+ }
105
+ logger.info('Shutting down blind peer')
20
106
  await blindPeer.close()
107
+ logger.info('Shut down blind peer')
21
108
  })
22
109
 
110
+ if (exposeRepl) {
111
+ logger.warn('Setting up REPL swarm, enabling remote access to this process')
112
+ const replSwarm = require('repl-swarm')
113
+ const seed = replSwarm({ blindPeer, instrumentation })
114
+ setInterval(
115
+ () => {
116
+ logger.info(`REPL swarm available at ${seed}`)
117
+ }, 1000 * 60 * 60
118
+ )
119
+ }
120
+
23
121
  await blindPeer.listen()
24
122
 
25
- console.info(`Listening at ${idEnc.normalize(blindPeer.publicKey)}`)
123
+ logger.info(`Blind peer listening, local address is ${blindPeer.swarm.dht.localAddress().host}:${blindPeer.swarm.dht.localAddress().port}`)
124
+ logger.info(`Bytes allocated: ${byteSize(blindPeer.digest.bytesAllocated)} of ${byteSize(blindPeer.maxBytes)}`)
125
+
126
+ if (debug) {
127
+ blindPeer.swarm.on('connection', (conn, peerInfo) => {
128
+ const key = idEnc.normalize(peerInfo.publicKey)
129
+ logger.debug(`Opened connection to ${key}`)
130
+ conn.on('close', () => logger.debug(`Closed connection to ${key}`))
131
+ })
132
+ }
133
+
134
+ if (flags.autodiscoveryRpcKey) {
135
+ const autodiscoveryRpcKey = idEnc.decode(flags.autodiscoveryRpcKey)
136
+ const seed = idEnc.decode(flags.autodiscoverySeed)
137
+ const serviceName = flags.autodiscoveryServiceName || SERVICE_NAME
138
+ const registerClient = new RegisterClient(autodiscoveryRpcKey, blindPeer.swarm.dht, seed)
139
+
140
+ // No need to block on this, so we run it in the background
141
+ logger.info(`Registering own RPC key rpc key ${idEnc.normalize(blindPeer.publicKey)} with service '${serviceName}' at autodiscovery service ${idEnc.normalize(autodiscoveryRpcKey)} (using public key ${idEnc.normalize(registerClient.keyPair.publicKey)})`)
142
+ registerClient.putService(blindPeer.publicKey, serviceName)
143
+ .then(() => { logger.info('Successfully requested to be added to the autodiscovery service') })
144
+ .catch(e => { logger.warn(`Failed to register to the autodiscovery service: ${e.stack}`) })
145
+ .finally(() => { registerClient.close().catch(safetyCatch) })
146
+ }
147
+
148
+ if (flags.scraperPublicKey) {
149
+ const swarm = blindPeer.swarm
150
+ logger.info('Setting up instrumentation')
151
+
152
+ const scraperPublicKey = idEnc.decode(flags.scraperPublicKey)
153
+ const scraperSecret = idEnc.decode(flags.scraperSecret)
154
+
155
+ let prometheusAlias = flags.scraperAlias
156
+ if (prometheusAlias && prometheusAlias.length > 99) throw new Error('The Prometheus alias must have length less than 100')
157
+ if (!prometheusAlias) {
158
+ prometheusAlias = `blind-peer-${idEnc.normalize(swarm.keyPair.publicKey)}`.slice(0, 99)
159
+ }
160
+
161
+ instrumentation = new Instrumentation({
162
+ swarm,
163
+ corestore: blindPeer.store,
164
+ scraperPublicKey,
165
+ prometheusAlias,
166
+ scraperSecret,
167
+ prometheusServiceName: SERVICE_NAME
168
+ })
169
+
170
+ blindPeer.registerMetrics(instrumentation.promClient)
171
+ instrumentation.registerLogger(logger)
172
+ await instrumentation.ready()
173
+ }
174
+
175
+ logger.info(`Listening at ${idEnc.normalize(blindPeer.publicKey)}`)
176
+ logger.info(`Encryption public key is ${idEnc.normalize(blindPeer.encryptionPublicKey)}`)
26
177
  }
27
178
  )
28
179
 
180
+ function recordToStr (record) {
181
+ return `DB Record for key ${idEnc.normalize(record.key)} with priority: ${record.priority}. Announcing? ${record.announce}`
182
+ }
183
+
184
+ function coreToInfo (core) {
185
+ return `${idEnc.normalize(core.key)} (${core.contiguousLength} / ${core.length}, ${core.peers.length} peers)`
186
+ }
187
+
29
188
  cmd.parse()