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/lib/db.js ADDED
@@ -0,0 +1,164 @@
1
+ const HyperDB = require('hyperdb')
2
+ const crypto = require('hypercore-crypto')
3
+ const ReadyResource = require('ready-resource')
4
+ const { definition: spec } = require('blind-peer-encodings')
5
+
6
+ // LOW, NORMAL, HIGH
7
+ const MAX_PRIO = 2
8
+
9
+ module.exports = class BlindPeerDB extends ReadyResource {
10
+ constructor (db, auth) {
11
+ super()
12
+
13
+ this.db = HyperDB.rocks(db, spec)
14
+ this.digest = null
15
+ this.auth = auth || null
16
+
17
+ this.encryptionKeyPair = null
18
+ this.swarmingKeyPair = null
19
+
20
+ this.coresAdding = []
21
+ this.coresUpdated = new Map()
22
+
23
+ this.ready().catch(noop)
24
+ }
25
+
26
+ find (col, q) {
27
+ return this.db.find(col, q)
28
+ }
29
+
30
+ get (col, q) {
31
+ return this.db.get(col, q)
32
+ }
33
+
34
+ getCoreRecord (key) {
35
+ return this.get('@blind-peer/cores', { key })
36
+ }
37
+
38
+ async _open () {
39
+ await this.db.ready()
40
+
41
+ const auth = await this.db.get('@blind-peer/auth')
42
+
43
+ this.auth = auth || this.auth || { swarming: null, encryption: null }
44
+ if (!this.auth.encryption) this.auth.encryption = crypto.randomBytes(32)
45
+ if (!this.auth.swarming) this.auth.swarming = crypto.randomBytes(32)
46
+
47
+ this.encryptionKeyPair = crypto.encryptionKeyPair(this.auth.encryption)
48
+ this.swarmingKeyPair = crypto.keyPair(this.auth.swarming)
49
+
50
+ const digest = await this.db.get('@blind-peer/digest')
51
+
52
+ this.digest = digest || { referrers: 0, cores: 0, bytesAllocated: 0, flushed: false }
53
+ this.digest.flushed = false
54
+
55
+ await this.db.insert('@blind-peer/auth', this.auth)
56
+ await this.db.insert('@blind-peer/digest', this.digest)
57
+ await this.db.flush()
58
+ }
59
+
60
+ async flush () { // The caller is responsible for ensuring this runs in a lock
61
+ if (!this.opened) await this.ready()
62
+
63
+ const coresAdding = this.coresAdding
64
+ const coresUpdated = this.coresUpdated
65
+
66
+ this.coresAdding = []
67
+ this.coresUpdated = new Map()
68
+
69
+ const tx = this.db.transaction()
70
+ const time = Date.now()
71
+
72
+ let addedCores = 0
73
+ let addedReferrers = 0
74
+ let bytesAllocated = 0
75
+
76
+ for (const info of coresAdding) {
77
+ const key = info.key
78
+ const existing = await tx.get('@blind-peer/cores', { key })
79
+ // TODO: test this path
80
+ if (existing) {
81
+ if (!info.announce && (info.priority || 0) <= existing.priority) continue // would be a downgrade, which we never want
82
+
83
+ existing.priority = Math.min(
84
+ Math.max(info.priority || 0, existing.priority)
85
+ )
86
+ existing.announce = info.announce || existing.announce
87
+ existing.updated = time
88
+ existing.active = time
89
+ await tx.insert('@blind-peer/cores', existing)
90
+ } else {
91
+ await tx.insert('@blind-peer/cores', {
92
+ key,
93
+ length: 0,
94
+ bytesAllocated: 0,
95
+ updated: time,
96
+ active: time,
97
+ priority: Math.min(MAX_PRIO, info.priority || 0),
98
+ announce: !!info.announce,
99
+ referrer: info.referrer || null,
100
+ blocksCleared: 0,
101
+ bytesCleared: 0
102
+ })
103
+
104
+ addedCores++
105
+ if (info.referrer) addedReferrers++
106
+ }
107
+ }
108
+
109
+ for (const core of coresUpdated.values()) {
110
+ const c = await tx.get('@blind-peer/cores', { key: core.key })
111
+ if (!c) continue // state mismatch
112
+
113
+ const updated = c.length !== core.length
114
+
115
+ bytesAllocated += (core.bytesAllocated - c.bytesAllocated)
116
+
117
+ c.length = core.length
118
+ c.bytesAllocated = core.bytesAllocated
119
+ c.bytesCleared = core.bytesCleared || 0
120
+ if (updated) c.updated = time
121
+ c.active = time
122
+ c.blocksCleared = core.blocksCleared || 0
123
+
124
+ await tx.insert('@blind-peer/cores', c)
125
+ }
126
+
127
+ if (addedCores || addedReferrers || bytesAllocated || this.closing) {
128
+ this.digest.cores += addedCores
129
+ this.digest.referrers += addedReferrers
130
+ this.digest.bytesAllocated += bytesAllocated
131
+ this.digest.flushed = !!this.closing
132
+
133
+ await tx.insert('@blind-peer/digest', this.digest)
134
+ }
135
+
136
+ await tx.flush()
137
+ }
138
+
139
+ addCore (info) {
140
+ this.coresAdding.push(info)
141
+ }
142
+
143
+ updateCore (core, id) { // TODO: id is technically optional
144
+ this.coresUpdated.set(id, core)
145
+ }
146
+
147
+ updated () {
148
+ return this.coresAdding.length > 0 || this.coresUpdated.size > 0
149
+ }
150
+
151
+ createGcCandidateReadStream () {
152
+ return this.db.find('@blind-peer/cores-by-activity')
153
+ }
154
+
155
+ createAnnouncingCoresStream () {
156
+ return this.db.find('@blind-peer/cores-by-announce')
157
+ }
158
+
159
+ async _close () {
160
+ await this.db.close()
161
+ }
162
+ }
163
+
164
+ function noop () {}
package/package.json CHANGED
@@ -1,37 +1,62 @@
1
1
  {
2
2
  "name": "blind-peer",
3
- "version": "0.0.3",
4
- "description": "WIP - nothing to see here",
3
+ "version": "2.7.4",
4
+ "description": "Blind peers help keep hypercores available",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "blind-peer": "bin.js"
8
8
  },
9
9
  "dependencies": {
10
- "autobase-light-writer": "^1.1.0",
11
- "corestore": "^6.18.4",
12
- "graceful-goodbye": "^1.3.2",
10
+ "autobase": "^7.0.18",
11
+ "autobase-discovery": "^1.0.0",
12
+ "b4a": "^1.6.7",
13
+ "blind-peer-encodings": "^3.0.0",
14
+ "compact-encoding": "^2.16.0",
15
+ "corestore": "^7.4.4",
16
+ "graceful-goodbye": "^1.3.3",
17
+ "hyper-instrument": "^2.0.0",
18
+ "hypercore": "^11.0.12",
19
+ "hypercore-crypto": "^3.5.0",
13
20
  "hypercore-id-encoding": "^1.3.0",
14
- "hyperdb": "^4.1.2",
15
- "hyperschema": "^1.0.3",
21
+ "hyperdb": "^4.9.4",
22
+ "hyperschema": "^1.10.3",
16
23
  "hyperswarm": "^4.8.4",
17
- "paparam": "^1.6.1",
18
- "protomux-rpc": "^1.6.0"
24
+ "paparam": "^1.8.0",
25
+ "pino": "^9.6.0",
26
+ "protomux-rpc": "^1.7.1",
27
+ "protomux-wakeup": "^2.2.0",
28
+ "ready-resource": "^1.1.2",
29
+ "repl-swarm": "^2.2.0",
30
+ "rocksdb-native": "^3.1.6",
31
+ "safety-catch": "^1.0.2",
32
+ "scope-lock": "^1.2.4",
33
+ "tiny-byte-size": "^1.1.0"
19
34
  },
20
35
  "devDependencies": {
36
+ "blind-peering": "^1.10.1",
37
+ "brittle": "^3.7.0",
21
38
  "debounceify": "^1.1.0",
22
- "standard": "^17.1.2"
39
+ "hyperdht": "^6.20.1",
40
+ "prom-client": "^15.1.3",
41
+ "standard": "^17.1.2",
42
+ "test-tmp": "^1.3.0"
23
43
  },
44
+ "files": [
45
+ "bin.js",
46
+ "index.js",
47
+ "lib/"
48
+ ],
24
49
  "scripts": {
25
- "test": "standard"
50
+ "test": "standard && brittle test/*.js"
26
51
  },
27
52
  "repository": {
28
53
  "type": "git",
29
- "url": "https://github.com/mafintosh/blind-peer.git"
54
+ "url": "git+https://github.com/holepunchto/blind-peer.git"
30
55
  },
31
56
  "author": "Holepunch Inc.",
32
57
  "license": "Apache-2.0",
33
58
  "bugs": {
34
- "url": "https://github.com/mafintosh/blind-peer/issues"
59
+ "url": "https://github.com/holepunchto/blind-peer/issues"
35
60
  },
36
- "homepage": "https://github.com/mafintosh/blind-peer"
61
+ "homepage": "https://github.com/holepunchto/blind-peer"
37
62
  }
@@ -1,23 +0,0 @@
1
- name: Build Status
2
- on:
3
- push:
4
- branches:
5
- - main
6
- pull_request:
7
- branches:
8
- - main
9
- jobs:
10
- build:
11
- strategy:
12
- matrix:
13
- node-version: [lts/*]
14
- os: [ubuntu-latest, macos-latest, windows-latest]
15
- runs-on: ${{ matrix.os }}
16
- steps:
17
- - uses: actions/checkout@v3
18
- - name: Use Node.js ${{ matrix.node-version }}
19
- uses: actions/setup-node@v3
20
- with:
21
- node-version: ${{ matrix.node-version }}
22
- - run: npm install
23
- - run: npm test
package/build.js DELETED
@@ -1,102 +0,0 @@
1
- const HyperDB = require('hyperdb/builder')
2
- const Hyperschema = require('hyperschema')
3
-
4
- const SCHEMA_DIR = './spec/hyperschema'
5
- const DB_DIR = './spec/hyperdb'
6
-
7
- const schema = Hyperschema.from(SCHEMA_DIR)
8
- const blind = schema.namespace('blind-peer')
9
-
10
- blind.register({
11
- name: 'request-mailbox',
12
- fields: [
13
- {
14
- name: 'autobase',
15
- type: 'fixed32',
16
- required: true
17
- },
18
- {
19
- name: 'blockEncryptionKey',
20
- type: 'fixed32'
21
- }
22
- ]
23
- })
24
-
25
- blind.register({
26
- name: 'response-mailbox',
27
- fields: [
28
- {
29
- name: 'autobase',
30
- type: 'fixed32',
31
- required: true
32
- },
33
- {
34
- name: 'writer',
35
- type: 'fixed32',
36
- required: true
37
- },
38
- {
39
- name: 'open',
40
- type: 'bool'
41
- }
42
- ]
43
- })
44
-
45
- blind.register({
46
- name: 'request-post',
47
- fields: [
48
- {
49
- name: 'autobase',
50
- type: 'fixed32',
51
- required: true
52
- },
53
- {
54
- name: 'message',
55
- type: 'buffer'
56
- }
57
- ]
58
- })
59
-
60
- blind.register({
61
- name: 'response-post',
62
- fields: [
63
- {
64
- name: 'length',
65
- type: 'uint',
66
- required: true
67
- }
68
- ]
69
- })
70
-
71
- blind.register({
72
- name: 'mailbox',
73
- fields: [
74
- {
75
- name: 'autobase',
76
- type: 'fixed32',
77
- required: true
78
- },
79
- {
80
- name: 'writer',
81
- type: 'fixed32',
82
- required: true
83
- },
84
- {
85
- name: 'blockEncryptionKey',
86
- type: 'fixed32'
87
- }
88
- ]
89
- })
90
-
91
- Hyperschema.toDisk(schema)
92
-
93
- const db = HyperDB.from(SCHEMA_DIR, DB_DIR, { offset: 64 })
94
- const blindDB = db.namespace('blind-peer')
95
-
96
- blindDB.collections.register({
97
- name: 'mailbox',
98
- schema: '@blind-peer/mailbox',
99
- key: ['autobase']
100
- })
101
-
102
- HyperDB.toDisk(db)
package/client.js DELETED
@@ -1,31 +0,0 @@
1
- const schema = require('./spec/hyperschema')
2
- const c = require('compact-encoding')
3
- const ProtomuxRPC = require('protomux-rpc')
4
-
5
- const addMailboxEncoding = {
6
- requestEncoding: schema.resolveStruct('@blind-peer/request-mailbox'),
7
- responseEncoding: schema.resolveStruct('@blind-peer/response-mailbox')
8
- }
9
-
10
- const postEncoding = {
11
- requestEncoding: schema.resolveStruct('@blind-peer/request-post'),
12
- responseEncoding: schema.resolveStruct('@blind-peer/response-post')
13
- }
14
-
15
- module.exports = class BlindPeerClient {
16
- constructor (stream) {
17
- this.stream = stream
18
- this.rpc = new ProtomuxRPC(stream, {
19
- id: stream.remotePublicKey,
20
- valueEncoding: c.none
21
- })
22
- }
23
-
24
- addMailbox (data) {
25
- return this.rpc.request('add-mailbox', data, addMailboxEncoding)
26
- }
27
-
28
- post ({ autobase, message }) {
29
- return this.rpc.request('post', { autobase, message }, postEncoding)
30
- }
31
- }
@@ -1,66 +0,0 @@
1
- import BlindPeerClient from '../client.js'
2
- import Autobase from 'autobase'
3
- import c from 'compact-encoding'
4
- import Corestore from 'corestore'
5
- import Hyperswarm from 'hyperswarm'
6
- import debounce from 'debounceify'
7
- import IdEnc from 'hypercore-id-encoding'
8
-
9
- const base = new Autobase(new Corestore('/tmp/my-corestore'), {
10
- encryptionKey: Buffer.alloc(30).fill('secret'),
11
- open (store) {
12
- return store.get('view', { valueEncoding: c.json })
13
- },
14
- async apply (nodes, view, base) {
15
- for (const node of nodes) {
16
- const jsonValue = JSON.parse(node.value.toString())
17
- if (jsonValue.add) await base.addWriter(Buffer.from(jsonValue.key, 'hex'), { indexer: false })
18
- view.append(jsonValue)
19
- }
20
- }
21
- })
22
-
23
- await base.ready()
24
- console.log('Autobase:', base.key.toString('hex'))
25
-
26
- base.view.on('append', debounce(async function () {
27
- base.ack() // ack for good messure
28
- console.log('someone appended to the autobase!')
29
- for (let i = 0; i < base.view.length; i++) {
30
- console.log(i, await base.view.get(i))
31
- }
32
- }))
33
-
34
- // TODO: record in autobase
35
- const publicKey = IdEnc.decode(process.argv[2])
36
-
37
- const s = new Hyperswarm({ keyPair: await base.store.createKeyPair('tmp') })
38
-
39
- s.on('connection', async c => {
40
- base.store.replicate(c)
41
-
42
- if (!c.remotePublicKey.equals(publicKey)) return
43
-
44
- const peer = new BlindPeerClient(c)
45
-
46
- const info = await peer.addMailbox({ autobase: base.key })
47
-
48
- if (info.open === false) {
49
- const message = Buffer.from(
50
- JSON.stringify({ add: true, key: info.writer.toString('hex') })
51
- )
52
- await base.append(message)
53
- await base.update()
54
-
55
- const core = base.store.get({ key: info.writer, active: false })
56
- await core.setEncryptionKey(base.encryptionKey)
57
- const req = { autobase: base.key, blockEncryptionKey: core.encryption.blockKey }
58
- await core.close()
59
-
60
- await peer.addMailbox(req)
61
-
62
- console.log('opened mailbox...')
63
- }
64
- })
65
-
66
- s.joinPeer(publicKey)
@@ -1,6 +0,0 @@
1
- import BlindPeer from '../index.js'
2
-
3
- const m = new BlindPeer('/tmp/blind-peer')
4
- await m.listen()
5
-
6
- console.log(m.publicKey.toString('hex'))
package/example/post.mjs DELETED
@@ -1,25 +0,0 @@
1
- import BlindPeerClient from '../client.js'
2
- import Hyperswarm from 'hyperswarm'
3
- import IdEnc from 'hypercore-id-encoding'
4
-
5
- const publicKey = IdEnc.decode(process.argv[2])
6
- const autobase = IdEnc.decode(process.argv[3])
7
- const rawMessage = process.argv[4]
8
- const message = Buffer.from(
9
- JSON.stringify({ mailbox: true, message: rawMessage })
10
- )
11
-
12
- const s = new Hyperswarm()
13
-
14
- s.on('connection', async c => {
15
- if (!c.remotePublicKey.equals(publicKey)) return
16
-
17
- const peer = new BlindPeerClient(c)
18
- const reply = await peer.post({ autobase, message })
19
-
20
- console.log(reply)
21
-
22
- s.destroy()
23
- })
24
-
25
- s.joinPeer(publicKey)
@@ -1,19 +0,0 @@
1
- {
2
- "version": 0,
3
- "offset": 64,
4
- "schema": [
5
- {
6
- "name": "mailbox",
7
- "namespace": "blind-peer",
8
- "id": 64,
9
- "type": 1,
10
- "indexes": [],
11
- "schema": "@blind-peer/mailbox",
12
- "derived": false,
13
- "key": [
14
- "autobase"
15
- ],
16
- "trigger": null
17
- }
18
- ]
19
- }
@@ -1,83 +0,0 @@
1
- // This file is autogenerated by the hyperdb compiler
2
- /* eslint-disable camelcase */
3
-
4
- const { IndexEncoder, c } = require('hyperdb/runtime')
5
-
6
- const { version, resolveStruct } = require('./messages.js')
7
-
8
- // '@blind-peer/mailbox' collection key
9
- const collection64_key = new IndexEncoder([
10
- IndexEncoder.BUFFER
11
- ], { prefix: 64 })
12
-
13
- function collection64_indexify (record) {
14
- const a = record.autobase
15
- return a === undefined ? [] : [a]
16
- }
17
-
18
- // '@blind-peer/mailbox' reconstruction function
19
- function collection64_reconstruct (version, keyBuf, valueBuf) {
20
- const key = collection64_key.decode(keyBuf)
21
- const value = c.decode(resolveStruct('@blind-peer/mailbox/value', version), valueBuf)
22
- // TODO: This should be fully code generated
23
- return {
24
- autobase: key[0],
25
- ...value
26
- }
27
- }
28
- // '@blind-peer/mailbox' key reconstruction function
29
- function collection64_reconstruct_key (keyBuf) {
30
- const key = collection64_key.decode(keyBuf)
31
- return {
32
- autobase: key[0]
33
- }
34
- }
35
-
36
- // '@blind-peer/mailbox'
37
- const collection64 = {
38
- name: '@blind-peer/mailbox',
39
- id: 64,
40
- encodeKey (record) {
41
- const key = [record.autobase]
42
- return collection64_key.encode(key)
43
- },
44
- encodeKeyRange ({ gt, lt, gte, lte } = {}) {
45
- return collection64_key.encodeRange({
46
- gt: gt ? collection64_indexify(gt) : null,
47
- lt: lt ? collection64_indexify(lt) : null,
48
- gte: gte ? collection64_indexify(gte) : null,
49
- lte: lte ? collection64_indexify(lte) : null
50
- })
51
- },
52
- encodeValue (version, record) {
53
- return c.encode(resolveStruct('@blind-peer/mailbox/value', version), record)
54
- },
55
- trigger: null,
56
- reconstruct: collection64_reconstruct,
57
- reconstructKey: collection64_reconstruct_key,
58
- indexes: []
59
- }
60
-
61
- module.exports = {
62
- version,
63
- collections: [
64
- collection64
65
- ],
66
- indexes: [
67
- ],
68
- resolveCollection,
69
- resolveIndex
70
- }
71
-
72
- function resolveCollection (name) {
73
- switch (name) {
74
- case '@blind-peer/mailbox': return collection64
75
- default: return null
76
- }
77
- }
78
-
79
- function resolveIndex (name) {
80
- switch (name) {
81
- default: return null
82
- }
83
- }