blind-peer 2.8.2 → 2.8.3
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 +3 -5
- package/bin.js +114 -40
- package/index.js +74 -52
- package/lib/db.js +23 -21
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -71,18 +71,16 @@ blind.addAutobaseBackground(autobase1)
|
|
|
71
71
|
|
|
72
72
|
// Add another core
|
|
73
73
|
blind.addCore(core1, autobase1.wakeupCapability.key)
|
|
74
|
-
|
|
75
74
|
```
|
|
76
75
|
|
|
77
76
|
Related services:
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
https://github.com/holepunchto/autobase-discovery
|
|
79
|
+
https://github.com/HDegroote/dht-prometheus
|
|
82
80
|
|
|
83
81
|
## Programmatic Usage
|
|
84
82
|
|
|
85
|
-
```
|
|
83
|
+
```js
|
|
86
84
|
const BlindPeer = require('blind-peer')
|
|
87
85
|
```
|
|
88
86
|
|
package/bin.js
CHANGED
|
@@ -16,20 +16,50 @@ const BlindPeer = require('.')
|
|
|
16
16
|
const SERVICE_NAME = 'blind-peer'
|
|
17
17
|
const DEFAULT_STORAGE_LIMIT_MB = 100_000
|
|
18
18
|
|
|
19
|
-
const cmd = command(
|
|
19
|
+
const cmd = command(
|
|
20
|
+
'blind-peer',
|
|
20
21
|
flag('--storage|-s [path]', 'Storage path, defaults to ./blind-peer'),
|
|
21
|
-
flag(
|
|
22
|
-
|
|
22
|
+
flag(
|
|
23
|
+
'--port|-p [int]',
|
|
24
|
+
'DHT Port to try to bind to. Only relevant when that port is not firewalled. (defaults to a random port)'
|
|
25
|
+
),
|
|
26
|
+
flag(
|
|
27
|
+
'--trusted-peer|-t [trusted-peer]',
|
|
28
|
+
'Public key of a trusted peer (allowed to set announce: true). Can be more than 1.'
|
|
29
|
+
).multiple(),
|
|
23
30
|
flag('--debug|-d', 'Enable debug mode (more logs)'),
|
|
24
|
-
flag(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
flag(
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
flag(
|
|
32
|
+
`--max-storage|-m [int]', 'Max storage usage, in Mb (defaults to ${DEFAULT_STORAGE_LIMIT_MB})`
|
|
33
|
+
),
|
|
34
|
+
flag(
|
|
35
|
+
'--autodiscovery-rpc-key [autodiscovery-rpc-key]',
|
|
36
|
+
'Public key where the autodiscovery service is listening. When set, the autodiscovery-seed must also be set. Can be hex or z32.'
|
|
37
|
+
),
|
|
38
|
+
flag(
|
|
39
|
+
'--autodiscovery-seed [autodiscovery-seed]',
|
|
40
|
+
'64-byte seed used to authenticate to the autodiscovery service. Can be hex or z32.'
|
|
41
|
+
),
|
|
42
|
+
flag(
|
|
43
|
+
'--autodiscovery-service-name [autodiscovery-service-name]',
|
|
44
|
+
`Name under which to register the service (default ${SERVICE_NAME})`
|
|
45
|
+
),
|
|
46
|
+
flag(
|
|
47
|
+
'--scraper-public-key [scraper-public-key]',
|
|
48
|
+
'Public key of a dht-prometheus scraper. Can be hex or z32.'
|
|
49
|
+
),
|
|
50
|
+
flag(
|
|
51
|
+
'--scraper-secret [scraper-secret]',
|
|
52
|
+
'Secret of the dht-prometheus scraper. Can be hex or z32.'
|
|
53
|
+
),
|
|
30
54
|
flag('--scraper-alias [scraper-alias]', '(optional) Alias with which to register to the scraper'),
|
|
31
|
-
flag(
|
|
32
|
-
|
|
55
|
+
flag(
|
|
56
|
+
'--log-streams',
|
|
57
|
+
'(Temporary, Advanced): enable debug logs on the UDX streams managed by the dht'
|
|
58
|
+
),
|
|
59
|
+
flag(
|
|
60
|
+
'--repl [repl]',
|
|
61
|
+
'Expose a repl-swarm at the passed-in seed (32 bytes in hex or z32 notation). Use for debugging only.'
|
|
62
|
+
),
|
|
33
63
|
async function ({ flags }) {
|
|
34
64
|
const debug = flags.debug
|
|
35
65
|
const logger = pino({
|
|
@@ -44,55 +74,75 @@ const cmd = command('blind-peer',
|
|
|
44
74
|
const port = flags.port ? parseInt(flags.port) : null
|
|
45
75
|
|
|
46
76
|
const maxBytes = 1_000_000 * parseInt(flags.maxStorage || DEFAULT_STORAGE_LIMIT_MB)
|
|
47
|
-
const trustedPubKeys = (flags.trustedPeer || []).map(k => idEnc.decode(k))
|
|
77
|
+
const trustedPubKeys = (flags.trustedPeer || []).map((k) => idEnc.decode(k))
|
|
48
78
|
|
|
49
79
|
const blindPeer = new BlindPeer(storage, { trustedPubKeys, maxBytes, port })
|
|
50
80
|
|
|
51
|
-
blindPeer.on('flush-error', e => {
|
|
81
|
+
blindPeer.on('flush-error', (e) => {
|
|
52
82
|
logger.warn(`Error while flushing the db: ${e.stack}`)
|
|
53
83
|
})
|
|
54
84
|
|
|
55
|
-
blindPeer.on('add-core', (record, _, stream) => {
|
|
85
|
+
blindPeer.on('add-new-core', (record, _, stream) => {
|
|
56
86
|
try {
|
|
57
|
-
|
|
87
|
+
if (record.announce) {
|
|
88
|
+
logger.info(
|
|
89
|
+
`add-core request received from peer ${streamToStr(stream)} for record ${recordToStr(record)}`
|
|
90
|
+
)
|
|
91
|
+
} else {
|
|
92
|
+
logger.debug(
|
|
93
|
+
`add-core request received from peer ${streamToStr(stream)} for record ${recordToStr(record)}`
|
|
94
|
+
)
|
|
95
|
+
}
|
|
58
96
|
} catch (e) {
|
|
59
97
|
logger.info(`Invalid add-core request received: ${e.stack}`)
|
|
60
98
|
logger.info(record)
|
|
61
99
|
}
|
|
62
100
|
})
|
|
63
101
|
blindPeer.on('delete-blocked', (stream, { key }) => {
|
|
64
|
-
logger.info(
|
|
102
|
+
logger.info(
|
|
103
|
+
`Blocked delete-core request from untrusted peer ${streamToStr(stream)} for core ${idEnc.normalize(key)}`
|
|
104
|
+
)
|
|
65
105
|
})
|
|
66
106
|
blindPeer.on('delete-core', (stream, { key, existing }) => {
|
|
67
|
-
logger.info(
|
|
107
|
+
logger.info(
|
|
108
|
+
`Received delete-core request from trusted peer ${streamToStr(stream)} for core ${idEnc.normalize(key)}. Existing: ${existing}`
|
|
109
|
+
)
|
|
68
110
|
})
|
|
69
111
|
blindPeer.on('delete-core-end', (stream, { key, announced }) => {
|
|
70
|
-
logger.info(
|
|
112
|
+
logger.info(
|
|
113
|
+
`Completed delete-core request from trusted peer ${streamToStr(stream)} for core ${idEnc.normalize(key)}. Was announced: ${announced}`
|
|
114
|
+
)
|
|
71
115
|
})
|
|
72
116
|
|
|
73
117
|
blindPeer.on('downgrade-announce', ({ record, remotePublicKey }) => {
|
|
74
118
|
try {
|
|
75
|
-
logger.info(
|
|
119
|
+
logger.info(
|
|
120
|
+
`Downgraded announce for peer ${idEnc.normalize(remotePublicKey)} because the peer is not trusted (Original: ${recordToStr(record)})`
|
|
121
|
+
)
|
|
76
122
|
} catch (e) {
|
|
77
123
|
logger.error(`Unexpected error while logging downgrade-announce: ${e.stack}`)
|
|
78
124
|
}
|
|
79
125
|
})
|
|
80
126
|
|
|
81
|
-
blindPeer.on('announce-core', core => {
|
|
127
|
+
blindPeer.on('announce-core', (core) => {
|
|
82
128
|
logger.info(`Started announcing core ${coreToInfo(core, true)}`)
|
|
83
129
|
})
|
|
84
|
-
blindPeer.on('core-downloaded', core => {
|
|
130
|
+
blindPeer.on('core-downloaded', (core) => {
|
|
85
131
|
logger.info(`Announced core fully downloaded: ${coreToInfo(core, true)}`)
|
|
86
132
|
})
|
|
87
|
-
blindPeer.on('core-append', core => {
|
|
133
|
+
blindPeer.on('core-append', (core) => {
|
|
88
134
|
logger.info(`Detected announced-core length update: ${coreToInfo(core, true)}`)
|
|
89
135
|
})
|
|
90
136
|
|
|
91
137
|
blindPeer.on('gc-start', ({ bytesToClear }) => {
|
|
92
|
-
logger.info(
|
|
138
|
+
logger.info(
|
|
139
|
+
`Starting GC, trying to clear ${byteSize(bytesToClear)} (bytes allocated: ${byteSize(blindPeer.digest.bytesAllocated)} of ${byteSize(blindPeer.maxBytes)})`
|
|
140
|
+
)
|
|
93
141
|
})
|
|
94
142
|
blindPeer.on('gc-done', ({ bytesCleared }) => {
|
|
95
|
-
logger.info(
|
|
143
|
+
logger.info(
|
|
144
|
+
`Completed GC, cleared ${byteSize(bytesCleared)} bytes (bytes allocated: ${byteSize(blindPeer.digest.bytesAllocated)} of ${byteSize(blindPeer.maxBytes)})`
|
|
145
|
+
)
|
|
96
146
|
})
|
|
97
147
|
if (debug) {
|
|
98
148
|
blindPeer.on('core-activity', (core) => {
|
|
@@ -104,12 +154,16 @@ const cmd = command('blind-peer',
|
|
|
104
154
|
const address = `${from.stream?.rawStream?.remoteHost}:${from.stream?.rawStream?.remotePort}`
|
|
105
155
|
const remotePubKey = idEnc.normalize(from.stream.remotePublicKey)
|
|
106
156
|
const key = idEnc.normalize(core.key)
|
|
107
|
-
logger.warn(
|
|
157
|
+
logger.warn(
|
|
158
|
+
`Received invalid request for core ${key} from peer ${remotePubKey} at ${address} (${err.stack})`
|
|
159
|
+
)
|
|
108
160
|
})
|
|
109
161
|
|
|
110
162
|
logger.info(`Using storage '${storage}'`)
|
|
111
163
|
if (trustedPubKeys.length > 0) {
|
|
112
|
-
logger.info(
|
|
164
|
+
logger.info(
|
|
165
|
+
`Trusted public keys:\n -${[...blindPeer.trustedPubKeys].map(idEnc.normalize).join('\n -')}`
|
|
166
|
+
)
|
|
113
167
|
}
|
|
114
168
|
|
|
115
169
|
let instrumentation = null
|
|
@@ -158,11 +212,16 @@ const cmd = command('blind-peer',
|
|
|
158
212
|
const pendingWrites = stream._wreqs.length - stream._wfree.length
|
|
159
213
|
if (pendingWrites >= 100) {
|
|
160
214
|
nrBigStreams++
|
|
161
|
-
logger.warn(
|
|
215
|
+
logger.warn(
|
|
216
|
+
`Stream ${stream.id} (remote id: ${stream.remoteId}) has ${pendingWrites} pending writes:\nStream JSON: ${JSON.stringify(stream.toJSON(), null, 1)}\nSocket json: ${stream.socket ? JSON.stringify(stream.socket.toJSON(), null, 1) : 'none'}\nhex streamhandle: ${b4a.toString(stream._handle, 'hex')}\nhex socket handle: ${stream.socket ? b4a.toString(stream.socket._handle, 'hex') : 'none'}`
|
|
217
|
+
)
|
|
162
218
|
}
|
|
163
219
|
}
|
|
164
|
-
if (nrBigStreams > 0)
|
|
165
|
-
|
|
220
|
+
if (nrBigStreams > 0) {
|
|
221
|
+
logger.warn(`Total streams with many pending writes: ${nrBigStreams}`)
|
|
222
|
+
}
|
|
223
|
+
} catch (e) {
|
|
224
|
+
// we don't want to crash the process with our debugging
|
|
166
225
|
logger.warn(`logStreams errored unexpectedly: ${e.stack}`)
|
|
167
226
|
}
|
|
168
227
|
}, 30_000)
|
|
@@ -170,8 +229,12 @@ const cmd = command('blind-peer',
|
|
|
170
229
|
|
|
171
230
|
await blindPeer.listen()
|
|
172
231
|
|
|
173
|
-
logger.info(
|
|
174
|
-
|
|
232
|
+
logger.info(
|
|
233
|
+
`Blind peer listening, local address is ${blindPeer.swarm.dht.localAddress().host}:${blindPeer.swarm.dht.localAddress().port}`
|
|
234
|
+
)
|
|
235
|
+
logger.info(
|
|
236
|
+
`Bytes allocated: ${byteSize(blindPeer.digest.bytesAllocated)} of ${byteSize(blindPeer.maxBytes)}`
|
|
237
|
+
)
|
|
175
238
|
|
|
176
239
|
if (flags.autodiscoveryRpcKey) {
|
|
177
240
|
const autodiscoveryRpcKey = idEnc.decode(flags.autodiscoveryRpcKey)
|
|
@@ -180,11 +243,20 @@ const cmd = command('blind-peer',
|
|
|
180
243
|
const registerClient = new RegisterClient(autodiscoveryRpcKey, blindPeer.swarm.dht, seed)
|
|
181
244
|
|
|
182
245
|
// No need to block on this, so we run it in the background
|
|
183
|
-
logger.info(
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
.
|
|
246
|
+
logger.info(
|
|
247
|
+
`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)})`
|
|
248
|
+
)
|
|
249
|
+
registerClient
|
|
250
|
+
.putService(blindPeer.publicKey, serviceName)
|
|
251
|
+
.then(() => {
|
|
252
|
+
logger.info('Successfully requested to be added to the autodiscovery service')
|
|
253
|
+
})
|
|
254
|
+
.catch((e) => {
|
|
255
|
+
logger.warn(`Failed to register to the autodiscovery service: ${e.stack}`)
|
|
256
|
+
})
|
|
257
|
+
.finally(() => {
|
|
258
|
+
registerClient.close().catch(safetyCatch)
|
|
259
|
+
})
|
|
188
260
|
}
|
|
189
261
|
|
|
190
262
|
if (flags.scraperPublicKey) {
|
|
@@ -195,7 +267,9 @@ const cmd = command('blind-peer',
|
|
|
195
267
|
const scraperSecret = idEnc.decode(flags.scraperSecret)
|
|
196
268
|
|
|
197
269
|
let prometheusAlias = flags.scraperAlias
|
|
198
|
-
if (prometheusAlias && prometheusAlias.length > 99)
|
|
270
|
+
if (prometheusAlias && prometheusAlias.length > 99) {
|
|
271
|
+
throw new Error('The Prometheus alias must have length less than 100')
|
|
272
|
+
}
|
|
199
273
|
if (!prometheusAlias) {
|
|
200
274
|
prometheusAlias = `blind-peer-${idEnc.normalize(swarm.keyPair.publicKey)}`.slice(0, 99)
|
|
201
275
|
}
|
|
@@ -219,17 +293,17 @@ const cmd = command('blind-peer',
|
|
|
219
293
|
}
|
|
220
294
|
)
|
|
221
295
|
|
|
222
|
-
function recordToStr
|
|
296
|
+
function recordToStr(record) {
|
|
223
297
|
const discKey = hypCrypto.discoveryKey(record.key)
|
|
224
298
|
return `DB Record for discovery key ${idEnc.normalize(discKey)} with priority: ${record.priority}. Announcing? ${record.announce}`
|
|
225
299
|
}
|
|
226
300
|
|
|
227
|
-
function streamToStr
|
|
301
|
+
function streamToStr(stream) {
|
|
228
302
|
const pubKey = idEnc.normalize(stream.remotePublicKey)
|
|
229
303
|
return `${pubKey}`
|
|
230
304
|
}
|
|
231
305
|
|
|
232
|
-
function coreToInfo
|
|
306
|
+
function coreToInfo(core, includePublicKey = false) {
|
|
233
307
|
const discKey = hypCrypto.discoveryKey(core.key)
|
|
234
308
|
let res = `Discovery key ${idEnc.normalize(discKey)} (${core.contiguousLength} / ${core.length}, ${core.peers.length} peers)`
|
|
235
309
|
if (includePublicKey) res += `. Public key: ${idEnc.normalize(core.key)}`
|
package/index.js
CHANGED
|
@@ -18,7 +18,7 @@ const { AddCoreEncoding } = require('blind-peer-encodings')
|
|
|
18
18
|
const { DeleteCoreEncoding } = require('blind-peer-encodings')
|
|
19
19
|
|
|
20
20
|
class CoreTracker {
|
|
21
|
-
constructor
|
|
21
|
+
constructor(blindPeer, core) {
|
|
22
22
|
this.blindPeer = blindPeer
|
|
23
23
|
this.core = core
|
|
24
24
|
this.destroyed = false
|
|
@@ -40,7 +40,7 @@ class CoreTracker {
|
|
|
40
40
|
this.core.on('append', onupdate)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
_onupdate
|
|
43
|
+
_onupdate() {
|
|
44
44
|
this.updated = true
|
|
45
45
|
if (!this.record) return
|
|
46
46
|
|
|
@@ -50,7 +50,7 @@ class CoreTracker {
|
|
|
50
50
|
this.blindPeer.flush().then(this.announceToReferrerBound, safetyCatch)
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
_onactive
|
|
53
|
+
_onactive() {
|
|
54
54
|
this.activated = true
|
|
55
55
|
|
|
56
56
|
if (this.record) {
|
|
@@ -60,7 +60,8 @@ class CoreTracker {
|
|
|
60
60
|
this.blindPeer.emit('core-activity', this.core, this.record)
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
gc
|
|
63
|
+
gc() {
|
|
64
|
+
// TODO: support gc-ing till less than last block (required hypercore to support getting byteLength at arbitrary versions)
|
|
64
65
|
const bytesCleared = this.core.byteLength
|
|
65
66
|
const blocksCleared = this.core.length
|
|
66
67
|
this.record.bytesAllocated = this.core.byteLength - bytesCleared
|
|
@@ -76,7 +77,7 @@ class CoreTracker {
|
|
|
76
77
|
return bytesCleared
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
async refresh
|
|
80
|
+
async refresh() {
|
|
80
81
|
await this.core.ready()
|
|
81
82
|
if (this.destroyed) return
|
|
82
83
|
|
|
@@ -93,11 +94,14 @@ class CoreTracker {
|
|
|
93
94
|
if (this.activated) this._onactive()
|
|
94
95
|
}
|
|
95
96
|
|
|
96
|
-
announceToReferrer
|
|
97
|
+
announceToReferrer() {
|
|
97
98
|
if (!this.record || !this.record.referrer) return
|
|
98
|
-
if (!this.referrerDiscoveryKey)
|
|
99
|
+
if (!this.referrerDiscoveryKey)
|
|
100
|
+
this.referrerDiscoveryKey = crypto.discoveryKey(this.record.referrer)
|
|
99
101
|
|
|
100
|
-
const sessions = this.blindPeer.wakeup.getSessions(null, {
|
|
102
|
+
const sessions = this.blindPeer.wakeup.getSessions(null, {
|
|
103
|
+
discoveryKey: this.referrerDiscoveryKey
|
|
104
|
+
})
|
|
101
105
|
if (sessions.length === 0) return
|
|
102
106
|
|
|
103
107
|
const wakeup = [{ key: this.core.key, length: this.core.length }]
|
|
@@ -116,21 +120,21 @@ class CoreTracker {
|
|
|
116
120
|
}
|
|
117
121
|
}
|
|
118
122
|
|
|
119
|
-
destroy
|
|
123
|
+
destroy() {
|
|
120
124
|
if (this.destroyed) return
|
|
121
125
|
this.destroyed = true
|
|
122
126
|
}
|
|
123
127
|
}
|
|
124
128
|
|
|
125
129
|
class WakeupHandler {
|
|
126
|
-
constructor
|
|
130
|
+
constructor(db, key, discoveryKey) {
|
|
127
131
|
this.db = db
|
|
128
132
|
this.key = key
|
|
129
133
|
this.discoveryKey = discoveryKey
|
|
130
134
|
this.active = false
|
|
131
135
|
}
|
|
132
136
|
|
|
133
|
-
async onpeeractive
|
|
137
|
+
async onpeeractive(peer, session) {
|
|
134
138
|
const referrer = this.key
|
|
135
139
|
const query = {
|
|
136
140
|
gte: { referrer },
|
|
@@ -150,7 +154,10 @@ class WakeupHandler {
|
|
|
150
154
|
}
|
|
151
155
|
|
|
152
156
|
class BlindPeer extends ReadyResource {
|
|
153
|
-
constructor
|
|
157
|
+
constructor(
|
|
158
|
+
rocks,
|
|
159
|
+
{ swarm, store, wakeup, maxBytes = 100_000_000_000, enableGc = true, trustedPubKeys, port } = {}
|
|
160
|
+
) {
|
|
154
161
|
super()
|
|
155
162
|
|
|
156
163
|
this.rocks = typeof rocks === 'string' ? new RocksDB(rocks) : rocks
|
|
@@ -181,36 +188,39 @@ class BlindPeer extends ReadyResource {
|
|
|
181
188
|
}
|
|
182
189
|
}
|
|
183
190
|
|
|
184
|
-
get encryptionPublicKey
|
|
191
|
+
get encryptionPublicKey() {
|
|
185
192
|
return this.db.encryptionKeyPair.publicKey
|
|
186
193
|
}
|
|
187
194
|
|
|
188
|
-
get publicKey
|
|
195
|
+
get publicKey() {
|
|
189
196
|
return this.swarm.keyPair.publicKey
|
|
190
197
|
}
|
|
191
198
|
|
|
192
|
-
get digest
|
|
199
|
+
get digest() {
|
|
193
200
|
return this.db.digest
|
|
194
201
|
}
|
|
195
202
|
|
|
196
|
-
get nrAnnouncedCores
|
|
203
|
+
get nrAnnouncedCores() {
|
|
197
204
|
return this.announcedCores.size
|
|
198
205
|
}
|
|
199
206
|
|
|
200
|
-
addTrustedPubKey
|
|
207
|
+
addTrustedPubKey(key) {
|
|
201
208
|
this.trustedPubKeys.add(IdEnc.normalize(key))
|
|
202
209
|
}
|
|
203
210
|
|
|
204
|
-
_isTrustedPeer
|
|
211
|
+
_isTrustedPeer(key) {
|
|
205
212
|
return this.trustedPubKeys.has(IdEnc.normalize(key))
|
|
206
213
|
}
|
|
207
214
|
|
|
208
|
-
async _open
|
|
215
|
+
async _open() {
|
|
209
216
|
await this.store.ready()
|
|
210
217
|
|
|
211
218
|
// legacy, we can remove once current ones are upgraded
|
|
212
219
|
const { secretKey } = await this.store.createKeyPair('blind-mirror-swarm')
|
|
213
|
-
this.db = new BlindPeerDB(this.rocks.session(), {
|
|
220
|
+
this.db = new BlindPeerDB(this.rocks.session(), {
|
|
221
|
+
swarming: secretKey.subarray(0, 32),
|
|
222
|
+
encryption: null
|
|
223
|
+
})
|
|
214
224
|
await this.db.ready()
|
|
215
225
|
|
|
216
226
|
// We don't need to track our own db, so we set this handler after the db core opened
|
|
@@ -218,7 +228,8 @@ class BlindPeer extends ReadyResource {
|
|
|
218
228
|
|
|
219
229
|
if (this.swarm === null) {
|
|
220
230
|
const swarmOpts = { keyPair: this.db.swarmingKeyPair }
|
|
221
|
-
if (this._port)
|
|
231
|
+
if (this._port)
|
|
232
|
+
swarmOpts.port = typeof this._port === 'number' ? [this._port, this._port + 64] : this._port
|
|
222
233
|
this.swarm = new Hyperswarm(swarmOpts)
|
|
223
234
|
}
|
|
224
235
|
this.swarm.on('connection', this._onconnection.bind(this))
|
|
@@ -232,7 +243,7 @@ class BlindPeer extends ReadyResource {
|
|
|
232
243
|
this.flushInterval = setInterval(this.flush.bind(this), 10_000)
|
|
233
244
|
}
|
|
234
245
|
|
|
235
|
-
async _onwakeup
|
|
246
|
+
async _onwakeup(discoveryKey, muxer) {
|
|
236
247
|
this.stats.wakeups++
|
|
237
248
|
|
|
238
249
|
const auth = await this.store.storage.getAuth(discoveryKey)
|
|
@@ -256,16 +267,17 @@ class BlindPeer extends ReadyResource {
|
|
|
256
267
|
stream.once('close', () => w.destroy())
|
|
257
268
|
}
|
|
258
269
|
|
|
259
|
-
async listen
|
|
270
|
+
async listen() {
|
|
260
271
|
if (!this.opened) await this.ready()
|
|
261
272
|
return this.swarm.listen()
|
|
262
273
|
}
|
|
263
274
|
|
|
264
|
-
needsGc
|
|
275
|
+
needsGc() {
|
|
265
276
|
return this.digest.bytesAllocated >= this.maxBytes
|
|
266
277
|
}
|
|
267
278
|
|
|
268
|
-
async _gc
|
|
279
|
+
async _gc() {
|
|
280
|
+
// Do not call directly (assumes lock)
|
|
269
281
|
if (!this.needsGc()) return
|
|
270
282
|
|
|
271
283
|
const bytesToClear = this.digest.bytesAllocated - this.maxBytes
|
|
@@ -302,7 +314,7 @@ class BlindPeer extends ReadyResource {
|
|
|
302
314
|
this.emit('gc-done', { bytesCleared })
|
|
303
315
|
}
|
|
304
316
|
|
|
305
|
-
_onreferrerupdates
|
|
317
|
+
_onreferrerupdates(updates) {
|
|
306
318
|
const pending = new Set()
|
|
307
319
|
|
|
308
320
|
for (const u of updates) {
|
|
@@ -319,7 +331,7 @@ class BlindPeer extends ReadyResource {
|
|
|
319
331
|
}
|
|
320
332
|
}
|
|
321
333
|
|
|
322
|
-
_oncoreopen
|
|
334
|
+
_oncoreopen(core) {
|
|
323
335
|
const session = new Hypercore({ core, weak: true })
|
|
324
336
|
const id = b4a.toString(core.discoveryKey, 'hex')
|
|
325
337
|
const tracker = new CoreTracker(this, session)
|
|
@@ -338,7 +350,8 @@ class BlindPeer extends ReadyResource {
|
|
|
338
350
|
})
|
|
339
351
|
}
|
|
340
352
|
|
|
341
|
-
async flush
|
|
353
|
+
async flush() {
|
|
354
|
+
// not allowed to throw
|
|
342
355
|
if (!(await this.lock.lock())) return
|
|
343
356
|
try {
|
|
344
357
|
if (this.enableGc && this.needsGc()) await this._gc()
|
|
@@ -351,7 +364,7 @@ class BlindPeer extends ReadyResource {
|
|
|
351
364
|
}
|
|
352
365
|
}
|
|
353
366
|
|
|
354
|
-
_onconnection
|
|
367
|
+
_onconnection(conn) {
|
|
355
368
|
if (this.closing) {
|
|
356
369
|
conn.destroy()
|
|
357
370
|
return
|
|
@@ -369,7 +382,7 @@ class BlindPeer extends ReadyResource {
|
|
|
369
382
|
rpc.respond('delete-core', DeleteCoreEncoding, this._ondeletecore.bind(this, conn))
|
|
370
383
|
}
|
|
371
384
|
|
|
372
|
-
async _activateCore
|
|
385
|
+
async _activateCore(stream, record) {
|
|
373
386
|
this.stats.activations++
|
|
374
387
|
|
|
375
388
|
const core = this.store.get({ key: record.key })
|
|
@@ -391,7 +404,7 @@ class BlindPeer extends ReadyResource {
|
|
|
391
404
|
stream.on('close', () => core.close().catch(safetyCatch))
|
|
392
405
|
}
|
|
393
406
|
|
|
394
|
-
async _announceCore
|
|
407
|
+
async _announceCore(key) {
|
|
395
408
|
const coreId = IdEnc.normalize(key)
|
|
396
409
|
if (this.announcedCores.has(coreId)) return
|
|
397
410
|
|
|
@@ -417,7 +430,7 @@ class BlindPeer extends ReadyResource {
|
|
|
417
430
|
this.emit('announce-core', core)
|
|
418
431
|
}
|
|
419
432
|
|
|
420
|
-
async _onaddcore
|
|
433
|
+
async _onaddcore(stream, record) {
|
|
421
434
|
if (!this.opened) await this.ready()
|
|
422
435
|
|
|
423
436
|
record.priority = Math.min(record.priority, 1) // 2 is reserved for trusted peers
|
|
@@ -433,6 +446,7 @@ class BlindPeer extends ReadyResource {
|
|
|
433
446
|
if (!existing || upgradeToAnnounce) {
|
|
434
447
|
this.db.addCore(record)
|
|
435
448
|
await this.flush() // flush now as important data
|
|
449
|
+
this.emit('add-new-core', record, true, stream)
|
|
436
450
|
}
|
|
437
451
|
|
|
438
452
|
if (record.referrer) {
|
|
@@ -457,13 +471,13 @@ class BlindPeer extends ReadyResource {
|
|
|
457
471
|
return coreRecord
|
|
458
472
|
}
|
|
459
473
|
|
|
460
|
-
async _ondeletecore
|
|
474
|
+
async _ondeletecore(stream, { key }) {
|
|
461
475
|
if (!this._isTrustedPeer(stream.remotePublicKey)) {
|
|
462
476
|
this.emit('delete-blocked', stream, { key })
|
|
463
477
|
throw new Error('Only trusted peers can delete cores')
|
|
464
478
|
}
|
|
465
479
|
|
|
466
|
-
const existing = await this.db.getCoreRecord(key) !== null
|
|
480
|
+
const existing = (await this.db.getCoreRecord(key)) !== null
|
|
467
481
|
this.emit('delete-core', stream, { key, existing })
|
|
468
482
|
if (!existing) return false
|
|
469
483
|
|
|
@@ -502,7 +516,7 @@ class BlindPeer extends ReadyResource {
|
|
|
502
516
|
return true
|
|
503
517
|
}
|
|
504
518
|
|
|
505
|
-
async _close
|
|
519
|
+
async _close() {
|
|
506
520
|
clearInterval(this.flushInterval)
|
|
507
521
|
if (this.ownsWakeup) this.wakeup.destroy()
|
|
508
522
|
if (this.ownsSwarm) await this.swarm.destroy()
|
|
@@ -512,68 +526,76 @@ class BlindPeer extends ReadyResource {
|
|
|
512
526
|
await this.rocks.close()
|
|
513
527
|
}
|
|
514
528
|
|
|
515
|
-
registerMetrics
|
|
529
|
+
registerMetrics(promClient) {
|
|
516
530
|
const self = this
|
|
517
|
-
new promClient.Gauge({
|
|
531
|
+
new promClient.Gauge({
|
|
532
|
+
// eslint-disable-line no-new
|
|
518
533
|
name: 'blind_peer_bytes_allocated',
|
|
519
534
|
help: 'The amount of bytes allocated by the hyperdb (as reported in its digest)',
|
|
520
|
-
collect
|
|
535
|
+
collect() {
|
|
521
536
|
this.set(self.digest.bytesAllocated)
|
|
522
537
|
}
|
|
523
538
|
})
|
|
524
539
|
|
|
525
|
-
new promClient.Gauge({
|
|
540
|
+
new promClient.Gauge({
|
|
541
|
+
// eslint-disable-line no-new
|
|
526
542
|
name: 'blind_peer_cores',
|
|
527
543
|
help: 'The amount of cores (as reported in its digest)',
|
|
528
|
-
collect
|
|
544
|
+
collect() {
|
|
529
545
|
this.set(self.digest.cores)
|
|
530
546
|
}
|
|
531
547
|
})
|
|
532
548
|
|
|
533
|
-
new promClient.Gauge({
|
|
549
|
+
new promClient.Gauge({
|
|
550
|
+
// eslint-disable-line no-new
|
|
534
551
|
name: 'blind_peer_cores_added',
|
|
535
552
|
help: 'The total amount of add-core RPC requests that have been processed',
|
|
536
|
-
collect
|
|
553
|
+
collect() {
|
|
537
554
|
this.set(self.stats.coresAdded)
|
|
538
555
|
}
|
|
539
556
|
})
|
|
540
557
|
|
|
541
|
-
new promClient.Gauge({
|
|
558
|
+
new promClient.Gauge({
|
|
559
|
+
// eslint-disable-line no-new
|
|
542
560
|
name: 'blind_peer_bytes_gcd',
|
|
543
561
|
help: 'The total amount of bytes garbage collected since the process started',
|
|
544
|
-
collect
|
|
562
|
+
collect() {
|
|
545
563
|
this.set(self.stats.bytesGcd)
|
|
546
564
|
}
|
|
547
565
|
})
|
|
548
566
|
|
|
549
|
-
new promClient.Gauge({
|
|
567
|
+
new promClient.Gauge({
|
|
568
|
+
// eslint-disable-line no-new
|
|
550
569
|
name: 'blind_peer_core_activations',
|
|
551
570
|
help: 'The total amount of hypercore activations since the process started',
|
|
552
|
-
collect
|
|
571
|
+
collect() {
|
|
553
572
|
this.set(self.stats.activations)
|
|
554
573
|
}
|
|
555
574
|
})
|
|
556
575
|
|
|
557
|
-
new promClient.Gauge({
|
|
576
|
+
new promClient.Gauge({
|
|
577
|
+
// eslint-disable-line no-new
|
|
558
578
|
name: 'blind_peer_wakeups',
|
|
559
579
|
help: 'The total amount of hypercore wakeups since the process started',
|
|
560
|
-
collect
|
|
580
|
+
collect() {
|
|
561
581
|
this.set(self.stats.wakeups)
|
|
562
582
|
}
|
|
563
583
|
})
|
|
564
584
|
|
|
565
|
-
new promClient.Gauge({
|
|
585
|
+
new promClient.Gauge({
|
|
586
|
+
// eslint-disable-line no-new
|
|
566
587
|
name: 'blind_peer_db_flushes',
|
|
567
588
|
help: 'The total amount of database flushes since the process started',
|
|
568
|
-
collect
|
|
589
|
+
collect() {
|
|
569
590
|
this.set(self.db.stats.flushes)
|
|
570
591
|
}
|
|
571
592
|
})
|
|
572
593
|
|
|
573
|
-
new promClient.Gauge({
|
|
594
|
+
new promClient.Gauge({
|
|
595
|
+
// eslint-disable-line no-new
|
|
574
596
|
name: 'blind_peer_announced_cores',
|
|
575
597
|
help: 'The amount of announced cores',
|
|
576
|
-
collect
|
|
598
|
+
collect() {
|
|
577
599
|
this.set(self.nrAnnouncedCores)
|
|
578
600
|
}
|
|
579
601
|
})
|
package/lib/db.js
CHANGED
|
@@ -8,7 +8,7 @@ const { definition: spec } = require('blind-peer-encodings')
|
|
|
8
8
|
const MAX_PRIO = 2
|
|
9
9
|
|
|
10
10
|
module.exports = class BlindPeerDB extends ReadyResource {
|
|
11
|
-
constructor
|
|
11
|
+
constructor(db, auth) {
|
|
12
12
|
super()
|
|
13
13
|
|
|
14
14
|
this.db = HyperDB.rocks(db, spec)
|
|
@@ -29,19 +29,19 @@ module.exports = class BlindPeerDB extends ReadyResource {
|
|
|
29
29
|
this.ready().catch(noop)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
find
|
|
32
|
+
find(col, q) {
|
|
33
33
|
return this.db.find(col, q)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
get
|
|
36
|
+
get(col, q) {
|
|
37
37
|
return this.db.get(col, q)
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
getCoreRecord
|
|
40
|
+
getCoreRecord(key) {
|
|
41
41
|
return this.get('@blind-peer/cores', { key })
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
async _open
|
|
44
|
+
async _open() {
|
|
45
45
|
await this.db.ready()
|
|
46
46
|
|
|
47
47
|
const auth = await this.db.get('@blind-peer/auth')
|
|
@@ -63,7 +63,8 @@ module.exports = class BlindPeerDB extends ReadyResource {
|
|
|
63
63
|
await this.db.flush()
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
async flush
|
|
66
|
+
async flush() {
|
|
67
|
+
// The caller is responsible for ensuring this runs in a lock
|
|
67
68
|
if (!this.opened) await this.ready()
|
|
68
69
|
|
|
69
70
|
const coresAdding = this.coresAdding
|
|
@@ -96,9 +97,7 @@ module.exports = class BlindPeerDB extends ReadyResource {
|
|
|
96
97
|
if (existing) {
|
|
97
98
|
if (!info.announce && (info.priority || 0) <= existing.priority) continue // would be a downgrade, which we never want
|
|
98
99
|
|
|
99
|
-
existing.priority = Math.min(
|
|
100
|
-
Math.max(info.priority || 0, existing.priority)
|
|
101
|
-
)
|
|
100
|
+
existing.priority = Math.min(Math.max(info.priority || 0, existing.priority))
|
|
102
101
|
existing.announce = info.announce || existing.announce
|
|
103
102
|
existing.updated = time
|
|
104
103
|
existing.active = time
|
|
@@ -128,7 +127,7 @@ module.exports = class BlindPeerDB extends ReadyResource {
|
|
|
128
127
|
|
|
129
128
|
const updated = c.length !== core.length
|
|
130
129
|
|
|
131
|
-
bytesAllocated +=
|
|
130
|
+
bytesAllocated += core.bytesAllocated - c.bytesAllocated
|
|
132
131
|
|
|
133
132
|
c.length = core.length
|
|
134
133
|
c.bytesAllocated = core.bytesAllocated
|
|
@@ -153,38 +152,41 @@ module.exports = class BlindPeerDB extends ReadyResource {
|
|
|
153
152
|
await tx.flush()
|
|
154
153
|
}
|
|
155
154
|
|
|
156
|
-
async hasCore
|
|
155
|
+
async hasCore(key) {
|
|
157
156
|
key = IdEnc.decode(key)
|
|
158
|
-
return await this.db.get('@blind-peer/cores', { key }) !== null
|
|
157
|
+
return (await this.db.get('@blind-peer/cores', { key })) !== null
|
|
159
158
|
}
|
|
160
159
|
|
|
161
|
-
addCore
|
|
160
|
+
addCore(info) {
|
|
162
161
|
this.coresAdding.push(info)
|
|
163
162
|
}
|
|
164
163
|
|
|
165
|
-
deleteCore
|
|
164
|
+
deleteCore(key) {
|
|
166
165
|
this.coresDeleting.push(key)
|
|
167
166
|
}
|
|
168
167
|
|
|
169
|
-
updateCore
|
|
168
|
+
updateCore(core, id) {
|
|
169
|
+
// TODO: id is technically optional
|
|
170
170
|
this.coresUpdated.set(id, core)
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
updated
|
|
174
|
-
return
|
|
173
|
+
updated() {
|
|
174
|
+
return (
|
|
175
|
+
this.coresAdding.length > 0 || this.coresUpdated.size > 0 || this.coresDeleting.length > 0
|
|
176
|
+
)
|
|
175
177
|
}
|
|
176
178
|
|
|
177
|
-
createGcCandidateReadStream
|
|
179
|
+
createGcCandidateReadStream() {
|
|
178
180
|
return this.db.find('@blind-peer/cores-by-activity')
|
|
179
181
|
}
|
|
180
182
|
|
|
181
|
-
createAnnouncingCoresStream
|
|
183
|
+
createAnnouncingCoresStream() {
|
|
182
184
|
return this.db.find('@blind-peer/cores-by-announce')
|
|
183
185
|
}
|
|
184
186
|
|
|
185
|
-
async _close
|
|
187
|
+
async _close() {
|
|
186
188
|
await this.db.close()
|
|
187
189
|
}
|
|
188
190
|
}
|
|
189
191
|
|
|
190
|
-
function noop
|
|
192
|
+
function noop() {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blind-peer",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.3",
|
|
4
4
|
"description": "Blind peers help keep hypercores available",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -37,8 +37,9 @@
|
|
|
37
37
|
"brittle": "^3.7.0",
|
|
38
38
|
"debounceify": "^1.1.0",
|
|
39
39
|
"hyperdht": "^6.20.1",
|
|
40
|
+
"prettier": "^3.6.2",
|
|
41
|
+
"prettier-config-holepunch": "^2.0.0",
|
|
40
42
|
"prom-client": "^15.1.3",
|
|
41
|
-
"standard": "^17.1.2",
|
|
42
43
|
"test-tmp": "^1.3.0"
|
|
43
44
|
},
|
|
44
45
|
"files": [
|
|
@@ -47,7 +48,9 @@
|
|
|
47
48
|
"lib/"
|
|
48
49
|
],
|
|
49
50
|
"scripts": {
|
|
50
|
-
"
|
|
51
|
+
"format": "prettier --write .",
|
|
52
|
+
"test": "prettier --check . && brittle test/*.js",
|
|
53
|
+
"test:bare": "bare test/basic.js"
|
|
51
54
|
},
|
|
52
55
|
"repository": {
|
|
53
56
|
"type": "git",
|