2
2
3
3
const Autobase = require ( 'autobase' )
4
4
const BlindPairing = require ( 'blind-pairing' )
5
- const Hyperbee = require ( 'hyperbee ' )
5
+ const HyperDB = require ( 'hyperdb ' )
6
6
const Hyperswarm = require ( 'hyperswarm' )
7
7
const ReadyResource = require ( 'ready-resource' )
8
8
const z32 = require ( 'z32' )
9
9
const b4a = require ( 'b4a' )
10
+ const { Router, dispatch } = require ( './spec/hyperdispatch' )
11
+ const db = require ( './spec/db/index.js' )
10
12
11
13
class AutopassPairer extends ReadyResource {
12
14
constructor ( store , invite , opts = { } ) {
13
15
super ( )
14
-
15
16
this . store = store
16
17
this . invite = invite
17
18
this . swarm = null
@@ -27,24 +28,21 @@ class AutopassPairer extends ReadyResource {
27
28
28
29
async _open ( ) {
29
30
await this . store . ready ( )
30
-
31
31
this . swarm = new Hyperswarm ( {
32
32
keyPair : await this . store . createKeyPair ( 'hyperswarm' ) ,
33
33
bootstrap : this . bootstrap
34
34
} )
35
35
36
- const store = this . store // we null this when passing it on, so avoid a nullptr
36
+ const store = this . store
37
37
this . swarm . on ( 'connection' , ( connection , peerInfo ) => {
38
38
store . replicate ( connection )
39
39
} )
40
40
41
41
this . pairing = new BlindPairing ( this . swarm )
42
-
43
42
const core = Autobase . getLocalCore ( this . store )
44
43
await core . ready ( )
45
44
const key = core . key
46
45
await core . close ( )
47
-
48
46
this . candidate = this . pairing . addCandidate ( {
49
47
invite : z32 . decode ( this . invite ) ,
50
48
userData : key ,
@@ -59,12 +57,23 @@ class AutopassPairer extends ReadyResource {
59
57
}
60
58
this . swarm = null
61
59
this . store = null
62
- if ( this . onresolve ) this . onresolve ( this . pass )
60
+ if ( this . onresolve ) this . _whenWritable ( )
63
61
this . candidate . close ( ) . catch ( noop )
64
62
}
65
63
} )
66
64
}
67
65
66
+ _whenWritable ( ) {
67
+ if ( this . pass . base . writable ) return
68
+ const check = ( ) => {
69
+ if ( this . pass . base . writable ) {
70
+ this . pass . base . off ( 'update' , check )
71
+ this . onresolve ( this . pass )
72
+ }
73
+ }
74
+ this . pass . base . on ( 'update' , check )
75
+ }
76
+
68
77
async _close ( ) {
69
78
if ( this . candidate !== null ) {
70
79
await this . candidate . close ( )
@@ -96,7 +105,7 @@ class AutopassPairer extends ReadyResource {
96
105
class Autopass extends ReadyResource {
97
106
constructor ( corestore , opts = { } ) {
98
107
super ( )
99
-
108
+ this . router = new Router ( )
100
109
this . store = corestore
101
110
this . swarm = opts . swarm || null
102
111
this . base = null
@@ -105,6 +114,26 @@ class Autopass extends ReadyResource {
105
114
this . pairing = null
106
115
this . replicate = opts . replicate !== false
107
116
this . debug = ! ! opts . key
117
+ // Register handlers for commands
118
+ this . router . add ( '@autopass/remove-writer' , async ( data , context ) => {
119
+ await context . base . removeWriter ( data . key )
120
+ } )
121
+
122
+ this . router . add ( '@autopass/add-writer' , async ( data , context ) => {
123
+ await context . base . addWriter ( data . key )
124
+ } )
125
+
126
+ this . router . add ( '@autopass/put' , async ( data , context ) => {
127
+ await context . view . insert ( '@autopass/records' , data )
128
+ } )
129
+
130
+ this . router . add ( '@autopass/del' , async ( data , context ) => {
131
+ await context . view . delete ( '@autopass/records' , { key : data . key } )
132
+ } )
133
+
134
+ this . router . add ( '@autopass/add-invite' , async ( data , context ) => {
135
+ await context . view . insert ( '@autopass/invite' , data )
136
+ } )
108
137
109
138
this . _boot ( opts )
110
139
this . ready ( ) . catch ( noop )
@@ -117,44 +146,33 @@ class Autopass extends ReadyResource {
117
146
this . base = new Autobase ( this . store , key , {
118
147
encrypt : true ,
119
148
encryptionKey,
120
- valueEncoding : 'json' ,
121
149
open ( store ) {
122
- return new Hyperbee ( store . get ( 'view' ) , {
150
+ return HyperDB . bee ( store . get ( 'view' ) , db , {
123
151
extension : false ,
124
- keyEncoding : 'utf-8' ,
125
- valueEncoding : 'json'
152
+ autoUpdate : true
126
153
} )
127
154
} ,
128
155
// New data blocks will be added using the apply function
129
- async apply ( nodes , view , base ) {
130
- for ( const node of nodes ) {
131
- const op = node . value
132
-
133
- // Add support for adding other peers as a writer to the base
134
- if ( op . type === 'addWriter' ) {
135
- await base . addWriter ( z32 . decode ( op . key ) )
136
- } else if ( op . type === 'removeWriter' ) {
137
- await base . removeWriter ( z32 . decode ( op . key ) )
138
- } else if ( op . type === 'addRecord' ) {
139
- // This adds a new record
140
- await view . put ( op . key , op . value )
141
- } else if ( op . type === 'removeRecord' ) {
142
- // Remove an existing record
143
- await view . del ( op . key )
144
- }
145
- }
146
- }
156
+ apply : this . _apply . bind ( this )
147
157
} )
148
158
149
- this . base . on ( 'update' , ( ) => this . emit ( 'update' ) )
159
+ this . base . on ( 'update' , ( ) => {
160
+ this . emit ( 'update' )
161
+ } )
162
+ }
163
+
164
+ async _apply ( nodes , view , base ) {
165
+ for ( const node of nodes ) {
166
+ await this . router . dispatch ( node . value , { view, base } )
167
+ }
168
+ await view . flush ( )
150
169
}
151
170
152
171
async _open ( ) {
153
172
await this . base . ready ( )
154
173
if ( this . replicate ) await this . _replicate ( )
155
174
}
156
175
157
- // Close the base
158
176
async _close ( ) {
159
177
if ( this . swarm ) {
160
178
await this . member . close ( )
@@ -164,23 +182,18 @@ class Autopass extends ReadyResource {
164
182
await this . base . close ( )
165
183
}
166
184
167
- // Need this key to become a writer
168
185
get writerKey ( ) {
169
186
return this . base . local . key
170
187
}
171
188
172
- // Return bootstrap key of the base
173
- // This is what other peers should use to bootstrap the base from
174
189
get key ( ) {
175
190
return this . base . key
176
191
}
177
192
178
- // Find peers in Hyperswarm using this
179
193
get discoveryKey ( ) {
180
194
return this . base . discoveryKey
181
195
}
182
196
183
- // Encryption key for the base
184
197
get encryptionKey ( ) {
185
198
return this . base . encryptionKey
186
199
}
@@ -191,101 +204,79 @@ class Autopass extends ReadyResource {
191
204
192
205
async createInvite ( opts ) {
193
206
if ( this . opened === false ) await this . ready ( )
194
- const existing = await this . get ( 'autopass/invite' )
195
- if ( existing ) return existing . invite
207
+ const existing = await this . base . view . findOne ( '@autopass/invite' , { } )
208
+ if ( existing ) {
209
+ return z32 . encode ( existing . invite )
210
+ }
196
211
const { id, invite, publicKey, expires } = BlindPairing . createInvite ( this . base . key )
197
- const record = { id : z32 . encode ( id ) , invite : z32 . encode ( invite ) , publicKey : z32 . encode ( publicKey ) , expires }
198
- await this . add ( 'autopass/invite' , record )
199
- return record . invite
212
+
213
+ const record = { id, invite, publicKey, expires }
214
+ await this . base . append ( dispatch ( '@autopass/add-invite' , record ) )
215
+ return z32 . encode ( record . invite )
200
216
}
201
217
202
- // Get data of all indexes in the base
203
218
list ( opts ) {
204
- return this . base . view . createReadStream ( opts )
219
+ return this . base . view . find ( '@autopass/records' , { } )
205
220
}
206
221
207
- // Get data stored in a specific key
208
222
async get ( key ) {
209
- const node = await this . base . view . get ( key )
210
- if ( node === null ) return null
211
- return node . value
223
+ const data = await this . base . view . get ( '@autopass/records' , { key } )
224
+ if ( data === null ) {
225
+ return null
226
+ }
227
+ return data . value
212
228
}
213
229
214
- // Add a peer as a writer
215
230
async addWriter ( key ) {
216
- await this . base . append ( {
217
- type : 'addWriter' ,
218
- key : b4a . isBuffer ( key ) ? z32 . encode ( key ) : key
219
- } )
220
-
231
+ await this . base . append ( dispatch ( '@autopass/add-writer' , { key : b4a . isBuffer ( key ) ? key : b4a . from ( key ) } ) )
221
232
return true
222
233
}
223
234
224
- // To later add removeWriter
225
235
async removeWriter ( key ) {
226
- await this . base . append ( {
227
- type : 'removeWriter' ,
228
- key : b4a . isBuffer ( key ) ? z32 . encode ( key ) : key
229
- } )
236
+ await this . base . append ( dispatch ( '@autopass/remove-writer' , { key : b4a . isBuffer ( key ) ? key : b4a . from ( key ) } ) )
230
237
}
231
238
232
- // Check if the base is writable
233
239
get writable ( ) {
234
240
return this . base . writable
235
241
}
236
242
237
- // Start Replicating the base across peers
238
243
async _replicate ( ) {
244
+ await this . base . ready ( )
239
245
if ( this . swarm === null ) {
240
246
this . swarm = new Hyperswarm ( {
241
247
keyPair : await this . store . createKeyPair ( 'hyperswarm' ) ,
242
248
bootstrap : this . bootstrap
243
249
} )
244
-
245
250
this . swarm . on ( 'connection' , ( connection , peerInfo ) => {
246
251
this . store . replicate ( connection )
247
252
} )
248
253
}
249
254
this . pairing = new BlindPairing ( this . swarm )
250
-
251
255
this . member = this . pairing . addMember ( {
252
256
discoveryKey : this . base . discoveryKey ,
253
257
onadd : async ( candidate ) => {
254
- const id = z32 . encode ( candidate . inviteId )
255
- const inv = await this . get ( 'autopass/invite' )
256
-
257
- if ( inv . id !== id ) return
258
-
259
- candidate . open ( z32 . decode ( inv . publicKey ) )
260
-
258
+ const id = candidate . inviteId
259
+ const inv = await this . base . view . findOne ( '@autopass/invite' , { } )
260
+ if ( ! b4a . equals ( inv . id , id ) ) {
261
+ return
262
+ }
263
+ candidate . open ( inv . publicKey )
261
264
await this . addWriter ( candidate . userData )
262
-
263
265
candidate . confirm ( {
264
266
key : this . base . key ,
265
267
encryptionKey : this . base . encryptionKey
266
268
} )
267
269
}
268
270
} )
269
-
270
271
this . swarm . join ( this . base . discoveryKey )
271
272
}
272
273
273
- // Append a key/value to the base
274
274
async add ( key , value ) {
275
- await this . base . append ( {
276
- type : 'addRecord' ,
277
- key,
278
- value
279
- } )
275
+ await this . base . append ( dispatch ( '@autopass/put' , { key, value } ) )
280
276
}
281
277
282
- // Remove a key pair
283
278
async remove ( key ) {
284
- await this . base . append ( {
285
- type : 'removeRecord' ,
286
- key,
287
- value : null
288
- } )
279
+ await this . base . append ( dispatch ( '@autopass/del' , { key } ) )
289
280
}
290
281
} // end class
291
282
0 commit comments