@leofcoin/peernet 1.1.57 → 1.1.58
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/.esdoc.json +10 -10
- package/.eslintrc.json +24 -24
- package/.gitattributes +2 -2
- package/.travis.yml +27 -27
- package/BREAKING_CHANGES.md +34 -34
- package/LICENSE +21 -21
- package/README.md +72 -72
- package/deploy.js +8 -8
- package/exports/browser/{index-329e0324.js → index-8868bdd8.js} +1 -1
- package/exports/browser/{messages-000b7f84.js → messages-eb6e5c71.js} +174 -174
- package/exports/browser/{peernet-bfbe6fff.js → peernet-87ea02a4.js} +2005 -1915
- package/exports/browser/peernet.d.ts +13 -11
- package/exports/browser/peernet.js +1 -1
- package/exports/{messages-dc960cb3.js → messages-b9a32987.js} +173 -173
- package/exports/peernet.js +288 -246
- package/exports/src/prompts/password.js +3 -3
- package/exports/store.js +7 -8
- package/exports/types/peernet.d.ts +13 -11
- package/index.html +19 -19
- package/package.json +70 -70
- package/rollup.config.js +76 -69
- package/src/dht/dht.ts +141 -141
- package/src/discovery/peer-discovery.js +75 -75
- package/src/errors/errors.js +12 -12
- package/src/handlers/data.js +11 -11
- package/src/handlers/message.js +34 -34
- package/src/identity.ts +101 -101
- package/src/messages/chat.js +14 -14
- package/src/messages/data-response.js +14 -14
- package/src/messages/data.js +18 -18
- package/src/messages/dht-response.js +14 -14
- package/src/messages/dht.js +22 -22
- package/src/messages/file-link.js +18 -18
- package/src/messages/file.js +18 -18
- package/src/messages/peer-response.js +14 -14
- package/src/messages/peer.js +13 -13
- package/src/messages/peernet.js +14 -14
- package/src/messages/ps.js +13 -13
- package/src/messages/request.js +14 -14
- package/src/messages/response.js +14 -14
- package/src/messages.js +13 -13
- package/src/peer-info.js +9 -9
- package/src/peernet.ts +848 -776
- package/src/prompts/password/node.js +5 -5
- package/src/proto/chat-message.proto.js +6 -6
- package/src/proto/data-response.proto.js +4 -4
- package/src/proto/data.proto.js +4 -4
- package/src/proto/dht-response.proto.js +4 -4
- package/src/proto/dht.proto.js +4 -4
- package/src/proto/file-link.proto.js +5 -5
- package/src/proto/file.proto.js +5 -5
- package/src/proto/peer-response.proto.js +3 -3
- package/src/proto/peer.proto.js +3 -3
- package/src/proto/peernet.proto.js +7 -7
- package/src/proto/ps.proto.js +4 -4
- package/src/proto/request.proto.js +4 -4
- package/src/proto/response.proto.js +3 -3
- package/src/types.ts +27 -27
- package/src/utils/utils.js +78 -78
- package/test/client.js +14 -14
- package/test/codec.js +56 -56
- package/test/hash.js +13 -13
- package/test/index.js +3 -3
- package/test/lastBlock.js +7 -7
- package/test/messages.js +26 -26
- package/test/peernet.js +17 -17
- package/test.js +64 -64
- package/test2.js +9 -9
- package/test3.js +15 -15
- package/test4.js +7 -7
- package/tsconfig.json +12 -12
package/src/peernet.ts
CHANGED
|
@@ -1,776 +1,848 @@
|
|
|
1
|
-
import
|
|
2
|
-
import PubSub from
|
|
3
|
-
import PeerDiscovery from
|
|
4
|
-
import DHT, { DHTProvider, DHTProviderDistanceResult } from
|
|
5
|
-
import { BufferToUint8Array, protoFor, target } from
|
|
6
|
-
import MessageHandler from
|
|
7
|
-
import dataHandler from
|
|
8
|
-
import { dhtError, nothingFoundError } from
|
|
9
|
-
import LeofcoinStorageClass from
|
|
10
|
-
import { utils as codecUtils } from
|
|
11
|
-
import Identity from
|
|
12
|
-
import swarm, { PeerId } from
|
|
13
|
-
import P2PTPeer from
|
|
14
|
-
|
|
15
|
-
globalThis.LeofcoinStorage = LeofcoinStorageClass
|
|
16
|
-
|
|
17
|
-
globalThis.leofcoin = globalThis.leofcoin || {}
|
|
18
|
-
globalThis.pubsub = globalThis.pubsub || new PubSub()
|
|
19
|
-
globalThis.globalSub = globalThis.globalSub || new PubSub()
|
|
20
|
-
|
|
21
|
-
declare global {
|
|
22
|
-
var LeofcoinStorage: typeof LeofcoinStorageClass
|
|
23
|
-
var peernet: Peernet
|
|
24
|
-
var pubsub: PubSub
|
|
25
|
-
var globalSub: PubSub
|
|
26
|
-
var blockStore: LeofcoinStorageClass
|
|
27
|
-
var transactionStore: LeofcoinStorageClass
|
|
28
|
-
var messageStore: LeofcoinStorageClass
|
|
29
|
-
var dataStore: LeofcoinStorageClass
|
|
30
|
-
var walletStore: LeofcoinStorageClass
|
|
31
|
-
var chainStore: LeofcoinStorageClass
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* @access public
|
|
36
|
-
* @example
|
|
37
|
-
* const peernet = new Peernet();
|
|
38
|
-
*/
|
|
39
|
-
export default class Peernet {
|
|
40
|
-
storePrefix: string
|
|
41
|
-
root: string
|
|
42
|
-
identity: Identity
|
|
43
|
-
stores: string[] = []
|
|
44
|
-
peerId: string
|
|
45
|
-
/**
|
|
46
|
-
* @type {Object}
|
|
47
|
-
* @property {Object} peer Instance of Peer
|
|
48
|
-
*/
|
|
49
|
-
dht: DHT = new DHT()
|
|
50
|
-
/** @leofcoin/peernet-swarm/client */
|
|
51
|
-
client: swarm
|
|
52
|
-
network: string
|
|
53
|
-
stars: string[]
|
|
54
|
-
networkVersion: string
|
|
55
|
-
bw: {
|
|
56
|
-
up: number
|
|
57
|
-
down: number
|
|
58
|
-
}
|
|
59
|
-
hasDaemon: boolean = false
|
|
60
|
-
autoStart: boolean = true
|
|
61
|
-
#starting: boolean = false
|
|
62
|
-
#started: boolean = false
|
|
63
|
-
#connections: {[index: PeerId]: P2PTPeer} = {}
|
|
64
|
-
requestProtos = {}
|
|
65
|
-
_messageHandler: MessageHandler
|
|
66
|
-
_peerHandler: PeerDiscovery
|
|
67
|
-
protos: {}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* @access public
|
|
71
|
-
* @param {Object} options
|
|
72
|
-
* @param {String} options.network - desired network
|
|
73
|
-
* @param {String} options.stars - star list for selected network (these should match, don't mix networks)
|
|
74
|
-
* @param {String} options.root - path to root directory
|
|
75
|
-
* @param {String} options.storePrefix - prefix for datatores (lfc)
|
|
76
|
-
*
|
|
77
|
-
* @return {Promise} instance of Peernet
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* const peernet = new Peernet({network: 'leofcoin', root: '.leofcoin'});
|
|
81
|
-
*/
|
|
82
|
-
constructor(options, password){
|
|
83
|
-
/**
|
|
84
|
-
* @property {String} network - current network
|
|
85
|
-
*/
|
|
86
|
-
this.network = options.network ||
|
|
87
|
-
this.autoStart = options.autoStart === undefined ? true : options.autoStart
|
|
88
|
-
this.stars = options.stars
|
|
89
|
-
const parts = this.network.split(
|
|
90
|
-
this.networkVersion =
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (!options.
|
|
94
|
-
if (!options.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
async
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
this
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
data
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
return
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
const
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
*
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
if (
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
1
|
+
import "@vandeurenglenn/debug";
|
|
2
|
+
import PubSub from "@vandeurenglenn/little-pubsub";
|
|
3
|
+
import PeerDiscovery from "./discovery/peer-discovery.js";
|
|
4
|
+
import DHT, { DHTProvider, DHTProviderDistanceResult } from "./dht/dht.js";
|
|
5
|
+
import { BufferToUint8Array, protoFor, target } from "./utils/utils.js";
|
|
6
|
+
import MessageHandler from "./handlers/message.js";
|
|
7
|
+
import dataHandler from "./handlers/data.js";
|
|
8
|
+
import { dhtError, nothingFoundError } from "./errors/errors.js";
|
|
9
|
+
import LeofcoinStorageClass from "@leofcoin/storage";
|
|
10
|
+
import { utils as codecUtils } from "@leofcoin/codecs";
|
|
11
|
+
import Identity from "./identity.js";
|
|
12
|
+
import swarm, { PeerId } from "@netpeer/p2pt-swarm";
|
|
13
|
+
import P2PTPeer from "@netpeer/p2pt-swarm/peer";
|
|
14
|
+
|
|
15
|
+
globalThis.LeofcoinStorage = LeofcoinStorageClass;
|
|
16
|
+
|
|
17
|
+
globalThis.leofcoin = globalThis.leofcoin || {};
|
|
18
|
+
globalThis.pubsub = globalThis.pubsub || new PubSub();
|
|
19
|
+
globalThis.globalSub = globalThis.globalSub || new PubSub();
|
|
20
|
+
|
|
21
|
+
declare global {
|
|
22
|
+
var LeofcoinStorage: typeof LeofcoinStorageClass;
|
|
23
|
+
var peernet: Peernet;
|
|
24
|
+
var pubsub: PubSub;
|
|
25
|
+
var globalSub: PubSub;
|
|
26
|
+
var blockStore: LeofcoinStorageClass;
|
|
27
|
+
var transactionStore: LeofcoinStorageClass;
|
|
28
|
+
var messageStore: LeofcoinStorageClass;
|
|
29
|
+
var dataStore: LeofcoinStorageClass;
|
|
30
|
+
var walletStore: LeofcoinStorageClass;
|
|
31
|
+
var chainStore: LeofcoinStorageClass;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @access public
|
|
36
|
+
* @example
|
|
37
|
+
* const peernet = new Peernet();
|
|
38
|
+
*/
|
|
39
|
+
export default class Peernet {
|
|
40
|
+
storePrefix: string;
|
|
41
|
+
root: string;
|
|
42
|
+
identity: Identity;
|
|
43
|
+
stores: string[] = [];
|
|
44
|
+
peerId: string;
|
|
45
|
+
/**
|
|
46
|
+
* @type {Object}
|
|
47
|
+
* @property {Object} peer Instance of Peer
|
|
48
|
+
*/
|
|
49
|
+
dht: DHT = new DHT();
|
|
50
|
+
/** @leofcoin/peernet-swarm/client */
|
|
51
|
+
client: swarm;
|
|
52
|
+
network: string;
|
|
53
|
+
stars: string[];
|
|
54
|
+
networkVersion: string;
|
|
55
|
+
bw: {
|
|
56
|
+
up: number;
|
|
57
|
+
down: number;
|
|
58
|
+
};
|
|
59
|
+
hasDaemon: boolean = false;
|
|
60
|
+
autoStart: boolean = true;
|
|
61
|
+
#starting: boolean = false;
|
|
62
|
+
#started: boolean = false;
|
|
63
|
+
#connections: { [index: PeerId]: P2PTPeer } = {};
|
|
64
|
+
requestProtos = {};
|
|
65
|
+
_messageHandler: MessageHandler;
|
|
66
|
+
_peerHandler: PeerDiscovery;
|
|
67
|
+
protos: {};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @access public
|
|
71
|
+
* @param {Object} options
|
|
72
|
+
* @param {String} options.network - desired network
|
|
73
|
+
* @param {String} options.stars - star list for selected network (these should match, don't mix networks)
|
|
74
|
+
* @param {String} options.root - path to root directory
|
|
75
|
+
* @param {String} options.storePrefix - prefix for datatores (lfc)
|
|
76
|
+
*
|
|
77
|
+
* @return {Promise} instance of Peernet
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* const peernet = new Peernet({network: 'leofcoin', root: '.leofcoin'});
|
|
81
|
+
*/
|
|
82
|
+
constructor(options, password) {
|
|
83
|
+
/**
|
|
84
|
+
* @property {String} network - current network
|
|
85
|
+
*/
|
|
86
|
+
this.network = options.network || "leofcoin";
|
|
87
|
+
this.autoStart = options.autoStart === undefined ? true : options.autoStart;
|
|
88
|
+
this.stars = options.stars;
|
|
89
|
+
const parts = this.network.split(":");
|
|
90
|
+
this.networkVersion =
|
|
91
|
+
options.networkVersion || parts.length > 1 ? parts[1] : "mainnet";
|
|
92
|
+
|
|
93
|
+
if (!options.storePrefix) options.storePrefix = "lfc";
|
|
94
|
+
if (!options.port) options.port = 2000;
|
|
95
|
+
if (!options.root) {
|
|
96
|
+
parts[1]
|
|
97
|
+
? (options.root = `.${parts[0]}/${parts[1]}`)
|
|
98
|
+
: (options.root = `.${this.network}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
globalThis.peernet = this;
|
|
102
|
+
this.bw = {
|
|
103
|
+
up: 0,
|
|
104
|
+
down: 0,
|
|
105
|
+
};
|
|
106
|
+
// @ts-ignore
|
|
107
|
+
return this._init(options, password);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
get id() {
|
|
111
|
+
return this.identity.id;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
get selectedAccount(): string {
|
|
115
|
+
return this.identity.selectedAccount;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
get accounts(): Promise<
|
|
119
|
+
[[name: string, externalAddress: string, internalAddress: string]]
|
|
120
|
+
> {
|
|
121
|
+
return this.identity.accounts;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
get defaultStores() {
|
|
125
|
+
return [
|
|
126
|
+
"account",
|
|
127
|
+
"wallet",
|
|
128
|
+
"block",
|
|
129
|
+
"transaction",
|
|
130
|
+
"chain",
|
|
131
|
+
"data",
|
|
132
|
+
"message",
|
|
133
|
+
];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
selectAccount(account: string) {
|
|
137
|
+
return this.identity.selectAccount(account);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
addProto(name, proto) {
|
|
141
|
+
if (!globalThis.peernet.protos[name])
|
|
142
|
+
globalThis.peernet.protos[name] = proto;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
addCodec(codec) {
|
|
146
|
+
return codecUtils.addCodec(codec);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async addStore(name, prefix, root, isPrivate = true) {
|
|
150
|
+
if (
|
|
151
|
+
name === "block" ||
|
|
152
|
+
name === "transaction" ||
|
|
153
|
+
name === "chain" ||
|
|
154
|
+
name === "data" ||
|
|
155
|
+
name === "message"
|
|
156
|
+
)
|
|
157
|
+
isPrivate = false;
|
|
158
|
+
|
|
159
|
+
let Storage;
|
|
160
|
+
|
|
161
|
+
this.hasDaemon
|
|
162
|
+
? (Storage = LeofcoinStorageClient)
|
|
163
|
+
: (Storage = LeofcoinStorage);
|
|
164
|
+
|
|
165
|
+
if (!globalThis[`${name}Store`]) {
|
|
166
|
+
globalThis[`${name}Store`] = new Storage(name, root);
|
|
167
|
+
await globalThis[`${name}Store`].init();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
globalThis[`${name}Store`].private = isPrivate;
|
|
171
|
+
if (!isPrivate) this.stores.push(name);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @see MessageHandler
|
|
176
|
+
*/
|
|
177
|
+
prepareMessage(data) {
|
|
178
|
+
return this._messageHandler.prepareMessage(data);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @access public
|
|
183
|
+
*
|
|
184
|
+
* @return {Array} peerId
|
|
185
|
+
*/
|
|
186
|
+
get peers() {
|
|
187
|
+
return Object.entries(this.#connections);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
get connections() {
|
|
191
|
+
return Object.values(this.#connections);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
get peerEntries() {
|
|
195
|
+
return Object.values(this.#connections);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @return {String} id - peerId
|
|
200
|
+
*/
|
|
201
|
+
getConnection(id) {
|
|
202
|
+
return this.connections[id];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* @private
|
|
207
|
+
*
|
|
208
|
+
* @param {Object} options
|
|
209
|
+
* @param {String} options.root - path to root directory
|
|
210
|
+
*
|
|
211
|
+
* @return {Promise} instance of Peernet
|
|
212
|
+
*/
|
|
213
|
+
async _init(
|
|
214
|
+
options: { storePrefix?: string; root?: string },
|
|
215
|
+
password: string
|
|
216
|
+
): Promise<Peernet> {
|
|
217
|
+
this.storePrefix = options.storePrefix;
|
|
218
|
+
this.root = options.root;
|
|
219
|
+
|
|
220
|
+
const {
|
|
221
|
+
RequestMessage,
|
|
222
|
+
ResponseMessage,
|
|
223
|
+
PeerMessage,
|
|
224
|
+
PeerMessageResponse,
|
|
225
|
+
PeernetMessage,
|
|
226
|
+
DHTMessage,
|
|
227
|
+
DHTMessageResponse,
|
|
228
|
+
DataMessage,
|
|
229
|
+
DataMessageResponse,
|
|
230
|
+
PsMessage,
|
|
231
|
+
ChatMessage,
|
|
232
|
+
PeernetFile,
|
|
233
|
+
// FolderMessageResponse
|
|
234
|
+
} = await import(/* webpackChunkName: "messages" */ "./messages.js");
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* proto Object containing protos
|
|
238
|
+
* @type {Object}
|
|
239
|
+
* @property {PeernetMessage} protos[peernet-message] messageNode
|
|
240
|
+
* @property {DHTMessage} protos[peernet-dht] messageNode
|
|
241
|
+
* @property {DHTMessageResponse} protos[peernet-dht-response] messageNode
|
|
242
|
+
* @property {DataMessage} protos[peernet-data] messageNode
|
|
243
|
+
* @property {DataMessageResponse} protos[peernet-data-response] messageNode
|
|
244
|
+
*/
|
|
245
|
+
|
|
246
|
+
globalThis.peernet.protos = {
|
|
247
|
+
"peernet-request": RequestMessage,
|
|
248
|
+
"peernet-response": ResponseMessage,
|
|
249
|
+
"peernet-peer": PeerMessage,
|
|
250
|
+
"peernet-peer-response": PeerMessageResponse,
|
|
251
|
+
"peernet-message": PeernetMessage,
|
|
252
|
+
"peernet-dht": DHTMessage,
|
|
253
|
+
"peernet-dht-response": DHTMessageResponse,
|
|
254
|
+
"peernet-data": DataMessage,
|
|
255
|
+
"peernet-data-response": DataMessageResponse,
|
|
256
|
+
"peernet-ps": PsMessage,
|
|
257
|
+
"chat-message": ChatMessage,
|
|
258
|
+
"peernet-file": PeernetFile,
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
this._messageHandler = new MessageHandler(this.network);
|
|
262
|
+
|
|
263
|
+
const { daemon, environment } = await target();
|
|
264
|
+
this.hasDaemon = daemon;
|
|
265
|
+
|
|
266
|
+
for (const store of this.defaultStores) {
|
|
267
|
+
await this.addStore(store, options.storePrefix, options.root);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
this.identity = new Identity(this.network);
|
|
271
|
+
await this.identity.load(password);
|
|
272
|
+
|
|
273
|
+
this._peerHandler = new PeerDiscovery(this.id);
|
|
274
|
+
this.peerId = this.id;
|
|
275
|
+
|
|
276
|
+
this.addRequestHandler("handshake", () => {
|
|
277
|
+
return new peernet.protos["peernet-response"]({
|
|
278
|
+
response: { peerId: this.id },
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
pubsub.subscribe("peer:discovered", async (peer) => {
|
|
283
|
+
// console.log(peer);
|
|
284
|
+
|
|
285
|
+
if (this.requestProtos["version"]) {
|
|
286
|
+
let data = await new globalThis.peernet.protos["peernet-request"]({
|
|
287
|
+
request: "version",
|
|
288
|
+
});
|
|
289
|
+
let node = await globalThis.peernet.prepareMessage(data);
|
|
290
|
+
let response = await peer.request(node.encoded);
|
|
291
|
+
response = await new globalThis.peernet.protos["peernet-response"](
|
|
292
|
+
new Uint8Array(Object.values(response))
|
|
293
|
+
);
|
|
294
|
+
peer.version = response.decoded.response.version;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
let data = await new globalThis.peernet.protos["peernet-request"]({
|
|
298
|
+
request: "handshake",
|
|
299
|
+
});
|
|
300
|
+
let node = await globalThis.peernet.prepareMessage(data);
|
|
301
|
+
let response = await peer.request(node.encoded);
|
|
302
|
+
|
|
303
|
+
response = await new globalThis.peernet.protos["peernet-response"](
|
|
304
|
+
new Uint8Array(Object.values(response))
|
|
305
|
+
);
|
|
306
|
+
// todo: response.decoded should be the response and not response.peerId
|
|
307
|
+
|
|
308
|
+
this.#connections[response.decoded.response.peerId] = peer;
|
|
309
|
+
pubsub.publish("peer:connected", peer);
|
|
310
|
+
// todo: cleanup discovered
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
pubsub.subscribe("peer:left", this.#peerLeft.bind(this));
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* converts data -> message -> proto
|
|
317
|
+
* @see DataHandler
|
|
318
|
+
*/
|
|
319
|
+
pubsub.subscribe("peer:data", dataHandler);
|
|
320
|
+
|
|
321
|
+
if (globalThis.navigator) {
|
|
322
|
+
globalThis.addEventListener("beforeunload", async () =>
|
|
323
|
+
this.client.destroy()
|
|
324
|
+
);
|
|
325
|
+
} else {
|
|
326
|
+
process.on("SIGTERM", async () => {
|
|
327
|
+
process.stdin.resume();
|
|
328
|
+
try {
|
|
329
|
+
await this.client.destroy();
|
|
330
|
+
} catch (error) {
|
|
331
|
+
// @ts-ignore
|
|
332
|
+
await this.client.close();
|
|
333
|
+
}
|
|
334
|
+
process.exit();
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
if (this.autoStart) await this.start();
|
|
338
|
+
return this;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async start() {
|
|
342
|
+
if (this.#starting || this.#started) return;
|
|
343
|
+
|
|
344
|
+
this.#starting = true;
|
|
345
|
+
const importee = await import("@netpeer/p2pt-swarm");
|
|
346
|
+
/**
|
|
347
|
+
* @access public
|
|
348
|
+
* @type {PeernetClient}
|
|
349
|
+
*/
|
|
350
|
+
this.client = new importee.default(
|
|
351
|
+
this.id,
|
|
352
|
+
this.networkVersion,
|
|
353
|
+
this.stars
|
|
354
|
+
);
|
|
355
|
+
this.#started = true;
|
|
356
|
+
this.#starting = false;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
#peerLeft(peer: P2PTPeer) {
|
|
360
|
+
for (const [id, _peer] of Object.entries(this.#connections)) {
|
|
361
|
+
if (
|
|
362
|
+
_peer.id === peer.id &&
|
|
363
|
+
this.#connections[id] &&
|
|
364
|
+
!this.#connections[id].connected
|
|
365
|
+
) {
|
|
366
|
+
delete this.#connections[id];
|
|
367
|
+
this.removePeer(_peer);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
addRequestHandler(name, method) {
|
|
373
|
+
this.requestProtos[name] = method;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
async sendMessage(peer, id, data) {
|
|
377
|
+
if (peer.connected) {
|
|
378
|
+
await peer.send(data, id);
|
|
379
|
+
this.bw.up += data.length;
|
|
380
|
+
} else this.removePeer(peer);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
async handleDHT(peer, id, proto) {
|
|
384
|
+
let { hash, store } = proto.decoded;
|
|
385
|
+
let has;
|
|
386
|
+
|
|
387
|
+
if (store) {
|
|
388
|
+
store = globalThis[`${store}Store`];
|
|
389
|
+
has = store.private ? false : await store.has(hash);
|
|
390
|
+
} else {
|
|
391
|
+
has = await this.has(hash);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const data = await new globalThis.peernet.protos["peernet-dht-response"]({
|
|
395
|
+
hash,
|
|
396
|
+
has,
|
|
397
|
+
});
|
|
398
|
+
const node = await this.prepareMessage(data);
|
|
399
|
+
|
|
400
|
+
this.sendMessage(peer, id, node.encoded);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
async handleData(peer, id, proto) {
|
|
404
|
+
let { hash, store } = proto.decoded;
|
|
405
|
+
let data;
|
|
406
|
+
store =
|
|
407
|
+
globalThis[`${store}Store`] ||
|
|
408
|
+
(await this.whichStore([...this.stores], hash));
|
|
409
|
+
|
|
410
|
+
if (store && !store.private) {
|
|
411
|
+
data = await store.get(hash);
|
|
412
|
+
|
|
413
|
+
if (data) {
|
|
414
|
+
data = await new globalThis.peernet.protos["peernet-data-response"]({
|
|
415
|
+
hash,
|
|
416
|
+
data,
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
const node = await this.prepareMessage(data);
|
|
420
|
+
this.sendMessage(peer, id, node.encoded);
|
|
421
|
+
}
|
|
422
|
+
} else {
|
|
423
|
+
// ban (trying to access private st)
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
async handleRequest(peer, id, proto) {
|
|
428
|
+
const method = this.requestProtos[proto.decoded.request];
|
|
429
|
+
if (method) {
|
|
430
|
+
const data = await method(proto.decoded.requested);
|
|
431
|
+
const node = await this.prepareMessage(data);
|
|
432
|
+
this.sendMessage(peer, id, node.encoded);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* @private
|
|
438
|
+
*
|
|
439
|
+
* @param {Buffer} message - peernet message
|
|
440
|
+
* @param {PeernetPeer} peer - peernet peer
|
|
441
|
+
*/
|
|
442
|
+
async _protoHandler(message, peer, from) {
|
|
443
|
+
const { id, proto } = message;
|
|
444
|
+
|
|
445
|
+
this.bw.down += proto.encoded.length;
|
|
446
|
+
switch (proto.name) {
|
|
447
|
+
case "peernet-dht": {
|
|
448
|
+
this.handleDHT(peer, id, proto);
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
case "peernet-data": {
|
|
452
|
+
this.handleData(peer, id, proto);
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
case "peernet-request": {
|
|
456
|
+
this.handleRequest(peer, id, proto);
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
case "peernet-ps": {
|
|
461
|
+
globalSub.publish(
|
|
462
|
+
new TextDecoder().decode(proto.decoded.topic),
|
|
463
|
+
proto.decoded.data
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* performs a walk and resolves first encounter
|
|
471
|
+
*
|
|
472
|
+
* @param {String} hash
|
|
473
|
+
*/
|
|
474
|
+
async walk(hash) {
|
|
475
|
+
if (!hash) throw new Error("hash expected, received undefined");
|
|
476
|
+
const data = await new globalThis.peernet.protos["peernet-dht"]({ hash });
|
|
477
|
+
const walk = async (peer, peerId) => {
|
|
478
|
+
const node = await this.prepareMessage(data);
|
|
479
|
+
let result = await peer.request(node.encoded);
|
|
480
|
+
result = new Uint8Array(Object.values(result));
|
|
481
|
+
const proto = await protoFor(result);
|
|
482
|
+
if (proto.name !== "peernet-dht-response") throw dhtError(proto.name);
|
|
483
|
+
|
|
484
|
+
const peerInfo = {
|
|
485
|
+
...peer.connectionStats,
|
|
486
|
+
id: peerId,
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
if (proto.decoded.has) this.dht.addProvider(peerInfo, proto.decoded.hash);
|
|
490
|
+
};
|
|
491
|
+
let walks = [];
|
|
492
|
+
for (const [peerId, peer] of Object.entries(this.#connections)) {
|
|
493
|
+
if (peerId !== this.id) {
|
|
494
|
+
walks.push(walk(peer, peerId));
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return Promise.all(walks);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Override DHT behavior, try's finding the content three times
|
|
502
|
+
*
|
|
503
|
+
* @param {String} hash
|
|
504
|
+
*/
|
|
505
|
+
async providersFor(hash: string, store?: undefined) {
|
|
506
|
+
let providers = this.dht.providersFor(hash);
|
|
507
|
+
// walk the network to find a provider
|
|
508
|
+
let tries = 0;
|
|
509
|
+
while (
|
|
510
|
+
(!providers && tries < 3) ||
|
|
511
|
+
(Object.keys(providers).length === 0 && tries < 3)
|
|
512
|
+
) {
|
|
513
|
+
tries += 1;
|
|
514
|
+
await this.walk(hash);
|
|
515
|
+
providers = this.dht.providersFor(hash);
|
|
516
|
+
}
|
|
517
|
+
// undefined if no providers given
|
|
518
|
+
return providers;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
get block() {
|
|
522
|
+
return {
|
|
523
|
+
get: async (hash: string) => {
|
|
524
|
+
const data = await blockStore.has(hash);
|
|
525
|
+
if (data) return blockStore.get(hash);
|
|
526
|
+
return this.requestData(hash, "block");
|
|
527
|
+
},
|
|
528
|
+
put: async (hash: string, data: Uint8Array) => {
|
|
529
|
+
if (await blockStore.has(hash)) return;
|
|
530
|
+
return await blockStore.put(hash, data);
|
|
531
|
+
},
|
|
532
|
+
has: async (hash: string) => await blockStore.has(hash),
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
get transaction() {
|
|
537
|
+
return {
|
|
538
|
+
get: async (hash: string) => {
|
|
539
|
+
const data = await transactionStore.has(hash);
|
|
540
|
+
if (data) return await transactionStore.get(hash);
|
|
541
|
+
return this.requestData(hash, "transaction");
|
|
542
|
+
},
|
|
543
|
+
put: async (hash: string, data: Uint8Array) => {
|
|
544
|
+
if (await transactionStore.has(hash)) return;
|
|
545
|
+
return await transactionStore.put(hash, data);
|
|
546
|
+
},
|
|
547
|
+
has: async (hash: string) => await transactionStore.has(hash),
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
async requestData(hash, store) {
|
|
552
|
+
const providers = await this.providersFor(hash);
|
|
553
|
+
if (!providers || (providers && Object.keys(providers).length === 0))
|
|
554
|
+
throw nothingFoundError(hash);
|
|
555
|
+
debug(`found ${Object.keys(providers).length} provider(s) for ${hash}`);
|
|
556
|
+
// get closest peer on earth
|
|
557
|
+
const closestPeer: DHTProvider = Object.values(providers)[0];
|
|
558
|
+
|
|
559
|
+
// get peer instance by id
|
|
560
|
+
if (!closestPeer || !closestPeer.id)
|
|
561
|
+
return this.requestData(hash, store?.name || store);
|
|
562
|
+
|
|
563
|
+
const id = closestPeer.id;
|
|
564
|
+
const peer = this.#connections[id];
|
|
565
|
+
|
|
566
|
+
if (peer?.connected) {
|
|
567
|
+
let data = await new globalThis.peernet.protos["peernet-data"]({
|
|
568
|
+
hash,
|
|
569
|
+
store: store?.name || store,
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
const node = await this.prepareMessage(data);
|
|
573
|
+
|
|
574
|
+
if (peer) data = await peer.request(node.encoded);
|
|
575
|
+
else {
|
|
576
|
+
// fallback and try every provider found
|
|
577
|
+
const promises = [];
|
|
578
|
+
const providers = await this.providersFor(hash, store);
|
|
579
|
+
for (const provider of Object.values(providers)) {
|
|
580
|
+
const peer = this.#connections[provider.id];
|
|
581
|
+
|
|
582
|
+
if (peer) promises.push(peer.request(node.encoded));
|
|
583
|
+
}
|
|
584
|
+
data = await Promise.race(promises);
|
|
585
|
+
}
|
|
586
|
+
if (data) data = new Uint8Array(Object.values(data));
|
|
587
|
+
|
|
588
|
+
const proto = await protoFor(data);
|
|
589
|
+
// TODO: store data automaticly or not
|
|
590
|
+
return BufferToUint8Array(proto.decoded.data);
|
|
591
|
+
|
|
592
|
+
// this.put(hash, proto.decoded.data)
|
|
593
|
+
} else {
|
|
594
|
+
this.dht.removeProvider(id, hash);
|
|
595
|
+
}
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
get message() {
|
|
600
|
+
return {
|
|
601
|
+
/**
|
|
602
|
+
* Get content for given message hash
|
|
603
|
+
*
|
|
604
|
+
* @param {String} hash
|
|
605
|
+
*/
|
|
606
|
+
get: async (hash) => {
|
|
607
|
+
debug(`get message ${hash}`);
|
|
608
|
+
const message = await messageStore.has(hash);
|
|
609
|
+
if (message) return await messageStore.get(hash);
|
|
610
|
+
return this.requestData(hash, "message");
|
|
611
|
+
},
|
|
612
|
+
/**
|
|
613
|
+
* put message content
|
|
614
|
+
*
|
|
615
|
+
* @param {String} hash
|
|
616
|
+
* @param {Buffer} message
|
|
617
|
+
*/
|
|
618
|
+
put: async (hash, message) => await messageStore.put(hash, message),
|
|
619
|
+
/**
|
|
620
|
+
* @param {String} hash
|
|
621
|
+
* @return {Boolean}
|
|
622
|
+
*/
|
|
623
|
+
has: async (hash) => await messageStore.has(hash),
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
get data() {
|
|
628
|
+
return {
|
|
629
|
+
/**
|
|
630
|
+
* Get content for given data hash
|
|
631
|
+
*
|
|
632
|
+
* @param {String} hash
|
|
633
|
+
*/
|
|
634
|
+
get: async (hash) => {
|
|
635
|
+
debug(`get data ${hash}`);
|
|
636
|
+
const data = await dataStore.has(hash);
|
|
637
|
+
if (data) return await dataStore.get(hash);
|
|
638
|
+
return this.requestData(hash, "data");
|
|
639
|
+
},
|
|
640
|
+
/**
|
|
641
|
+
* put data content
|
|
642
|
+
*
|
|
643
|
+
* @param {String} hash
|
|
644
|
+
* @param {Buffer} data
|
|
645
|
+
*/
|
|
646
|
+
put: async (hash, data) => await dataStore.put(hash, data),
|
|
647
|
+
/**
|
|
648
|
+
* @param {String} hash
|
|
649
|
+
* @return {Boolean}
|
|
650
|
+
*/
|
|
651
|
+
has: async (hash) => await dataStore.has(hash),
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
get folder() {
|
|
656
|
+
return {
|
|
657
|
+
/**
|
|
658
|
+
* Get content for given data hash
|
|
659
|
+
*
|
|
660
|
+
* @param {String} hash
|
|
661
|
+
*/
|
|
662
|
+
get: async (hash) => {
|
|
663
|
+
debug(`get data ${hash}`);
|
|
664
|
+
const data = await dataStore.has(hash);
|
|
665
|
+
if (data) return await dataStore.get(hash);
|
|
666
|
+
return this.requestData(hash, "data");
|
|
667
|
+
},
|
|
668
|
+
/**
|
|
669
|
+
* put data content
|
|
670
|
+
*
|
|
671
|
+
* @param {String} hash
|
|
672
|
+
* @param {Buffer} data
|
|
673
|
+
*/
|
|
674
|
+
put: async (hash, data) => await dataStore.put(hash, data),
|
|
675
|
+
/**
|
|
676
|
+
* @param {String} hash
|
|
677
|
+
* @return {Boolean}
|
|
678
|
+
*/
|
|
679
|
+
has: async (hash) => await dataStore.has(hash),
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
async addFolder(files) {
|
|
684
|
+
const links = [];
|
|
685
|
+
for (const file of files) {
|
|
686
|
+
const fileNode = await new globalThis.peernet.protos["peernet-file"](
|
|
687
|
+
file
|
|
688
|
+
);
|
|
689
|
+
const hash = await fileNode.hash;
|
|
690
|
+
await dataStore.put(hash, fileNode.encoded);
|
|
691
|
+
links.push({ hash, path: file.path });
|
|
692
|
+
}
|
|
693
|
+
const node = await new globalThis.peernet.protos["peernet-file"]({
|
|
694
|
+
path: "/",
|
|
695
|
+
links,
|
|
696
|
+
});
|
|
697
|
+
const hash = await node.hash;
|
|
698
|
+
await dataStore.put(hash, node.encoded);
|
|
699
|
+
|
|
700
|
+
return hash;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
async ls(hash, options) {
|
|
704
|
+
let data;
|
|
705
|
+
const has = await dataStore.has(hash);
|
|
706
|
+
data = has
|
|
707
|
+
? await dataStore.get(hash)
|
|
708
|
+
: await this.requestData(hash, "data");
|
|
709
|
+
|
|
710
|
+
const node = await new peernet.protos["peernet-file"](data);
|
|
711
|
+
await node.decode();
|
|
712
|
+
console.log(data);
|
|
713
|
+
const paths = [];
|
|
714
|
+
if (node.decoded?.links.length === 0) throw new Error(`${hash} is a file`);
|
|
715
|
+
for (const { path, hash } of node.decoded.links) {
|
|
716
|
+
paths.push({ path, hash });
|
|
717
|
+
}
|
|
718
|
+
if (options?.pin) await dataStore.put(hash, node.encoded);
|
|
719
|
+
return paths;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
async cat(hash, options) {
|
|
723
|
+
let data;
|
|
724
|
+
const has = await dataStore.has(hash);
|
|
725
|
+
data = has
|
|
726
|
+
? await dataStore.get(hash)
|
|
727
|
+
: await this.requestData(hash, "data");
|
|
728
|
+
const node = await new peernet.protos["peernet-file"](data);
|
|
729
|
+
|
|
730
|
+
if (node.decoded?.links.length > 0)
|
|
731
|
+
throw new Error(`${hash} is a directory`);
|
|
732
|
+
if (options?.pin) await dataStore.put(hash, node.encoded);
|
|
733
|
+
return node.decoded.content;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* goes trough given stores and tries to find data for given hash
|
|
738
|
+
* @param {Array} stores
|
|
739
|
+
* @param {string} hash
|
|
740
|
+
*/
|
|
741
|
+
async whichStore(stores, hash) {
|
|
742
|
+
let store = stores.pop();
|
|
743
|
+
const name = store;
|
|
744
|
+
store = globalThis[`${store}Store`];
|
|
745
|
+
if (store) {
|
|
746
|
+
const has = await store.has(hash);
|
|
747
|
+
if (has) return store;
|
|
748
|
+
if (stores.length > 0) return this.whichStore(stores, hash);
|
|
749
|
+
} else return;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Get content for given hash
|
|
754
|
+
*
|
|
755
|
+
* @param {String} hash - the hash of the wanted data
|
|
756
|
+
* @param {String} store - storeName to access
|
|
757
|
+
*/
|
|
758
|
+
async get(hash, store) {
|
|
759
|
+
debug(`get ${hash}`);
|
|
760
|
+
let data;
|
|
761
|
+
if (store) store = globalThis[`${store}Store`];
|
|
762
|
+
if (!store) store = await this.whichStore([...this.stores], hash);
|
|
763
|
+
if (store && (await store.has(hash))) data = await store.get(hash);
|
|
764
|
+
if (data) return data;
|
|
765
|
+
|
|
766
|
+
return this.requestData(hash, store?.name || store);
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* put content
|
|
771
|
+
*
|
|
772
|
+
* @param {String} hash
|
|
773
|
+
* @param {Buffer} data
|
|
774
|
+
* @param {String} storeName - storeName to access
|
|
775
|
+
*/
|
|
776
|
+
async put(
|
|
777
|
+
hash: string,
|
|
778
|
+
data: Uint8Array,
|
|
779
|
+
storeName: string | LeofcoinStorageClass = "data"
|
|
780
|
+
) {
|
|
781
|
+
const store: LeofcoinStorageClass = globalThis[`${storeName}Store`];
|
|
782
|
+
return store.put(hash, data);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* @param {String} hash
|
|
787
|
+
* @return {Boolean}
|
|
788
|
+
*/
|
|
789
|
+
async has(hash) {
|
|
790
|
+
const store = await this.whichStore([...this.stores], hash);
|
|
791
|
+
if (store) {
|
|
792
|
+
return store.private ? false : true;
|
|
793
|
+
}
|
|
794
|
+
return false;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
*
|
|
799
|
+
* @param {String} topic
|
|
800
|
+
* @param {String|Object|Array|Boolean|Buffer} data
|
|
801
|
+
*/
|
|
802
|
+
async publish(topic, data) {
|
|
803
|
+
// globalSub.publish(topic, data)
|
|
804
|
+
const id = Math.random().toString(36).slice(-12);
|
|
805
|
+
data = await new globalThis.peernet.protos["peernet-ps"]({ data, topic });
|
|
806
|
+
for (const [peerId, peer] of Object.entries(this.#connections)) {
|
|
807
|
+
if (peerId !== this.id) {
|
|
808
|
+
const node = await this.prepareMessage(data);
|
|
809
|
+
this.sendMessage(peer, id, node.encoded);
|
|
810
|
+
}
|
|
811
|
+
// TODO: if peer subscribed
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// createHash(data, name) {
|
|
816
|
+
// return new CodeHash(data, {name})
|
|
817
|
+
// }
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
*
|
|
821
|
+
* @param {String} topic
|
|
822
|
+
* @param {Method} cb
|
|
823
|
+
*/
|
|
824
|
+
async subscribe(topic: string, callback: Function) {
|
|
825
|
+
// TODO: if peer subscribed
|
|
826
|
+
globalSub.subscribe(topic, callback);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
async removePeer(peer) {
|
|
830
|
+
console.log("removepeer", peer.id);
|
|
831
|
+
const id = peer.id;
|
|
832
|
+
await this.client._removePeer(peer);
|
|
833
|
+
if (this.client.peers[id]) {
|
|
834
|
+
for (const connection of Object.keys(this.client.peers[id])) {
|
|
835
|
+
// if (this.client.peers[id][connection].connected === false) delete this.client.peers[id][connection]
|
|
836
|
+
// @ts-ignore
|
|
837
|
+
if (this.client.peers[id][connection].connected)
|
|
838
|
+
return this.client.emit("peerconnect", connection);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
get Buffer() {
|
|
844
|
+
return Buffer;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
globalThis.Peernet = Peernet;
|