@helia/bitswap 0.0.0-329652a
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/LICENSE +4 -0
- package/README.md +64 -0
- package/dist/index.min.js +3 -0
- package/dist/src/bitswap.d.ts +50 -0
- package/dist/src/bitswap.d.ts.map +1 -0
- package/dist/src/bitswap.js +120 -0
- package/dist/src/bitswap.js.map +1 -0
- package/dist/src/constants.d.ts +12 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +12 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/index.d.ts +178 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +12 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/network.d.ts +84 -0
- package/dist/src/network.d.ts.map +1 -0
- package/dist/src/network.js +370 -0
- package/dist/src/network.js.map +1 -0
- package/dist/src/pb/message.d.ts +67 -0
- package/dist/src/pb/message.d.ts.map +1 -0
- package/dist/src/pb/message.js +359 -0
- package/dist/src/pb/message.js.map +1 -0
- package/dist/src/peer-want-lists/index.d.ts +44 -0
- package/dist/src/peer-want-lists/index.d.ts.map +1 -0
- package/dist/src/peer-want-lists/index.js +116 -0
- package/dist/src/peer-want-lists/index.js.map +1 -0
- package/dist/src/peer-want-lists/ledger.d.ts +54 -0
- package/dist/src/peer-want-lists/ledger.d.ts.map +1 -0
- package/dist/src/peer-want-lists/ledger.js +104 -0
- package/dist/src/peer-want-lists/ledger.js.map +1 -0
- package/dist/src/session.d.ts +20 -0
- package/dist/src/session.d.ts.map +1 -0
- package/dist/src/session.js +100 -0
- package/dist/src/session.js.map +1 -0
- package/dist/src/stats.d.ts +16 -0
- package/dist/src/stats.d.ts.map +1 -0
- package/dist/src/stats.js +49 -0
- package/dist/src/stats.js.map +1 -0
- package/dist/src/utils/cid-prefix.d.ts +3 -0
- package/dist/src/utils/cid-prefix.d.ts.map +1 -0
- package/dist/src/utils/cid-prefix.js +7 -0
- package/dist/src/utils/cid-prefix.js.map +1 -0
- package/dist/src/utils/varint-decoder.d.ts +3 -0
- package/dist/src/utils/varint-decoder.d.ts.map +1 -0
- package/dist/src/utils/varint-decoder.js +15 -0
- package/dist/src/utils/varint-decoder.js.map +1 -0
- package/dist/src/utils/varint-encoder.d.ts +3 -0
- package/dist/src/utils/varint-encoder.d.ts.map +1 -0
- package/dist/src/utils/varint-encoder.js +14 -0
- package/dist/src/utils/varint-encoder.js.map +1 -0
- package/dist/src/want-list.d.ts +120 -0
- package/dist/src/want-list.d.ts.map +1 -0
- package/dist/src/want-list.js +361 -0
- package/dist/src/want-list.js.map +1 -0
- package/package.json +200 -0
- package/src/bitswap.ts +152 -0
- package/src/constants.ts +11 -0
- package/src/index.ts +215 -0
- package/src/network.ts +506 -0
- package/src/pb/message.proto +42 -0
- package/src/pb/message.ts +450 -0
- package/src/peer-want-lists/index.ts +165 -0
- package/src/peer-want-lists/ledger.ts +161 -0
- package/src/session.ts +150 -0
- package/src/stats.ts +67 -0
- package/src/utils/cid-prefix.ts +8 -0
- package/src/utils/varint-decoder.ts +19 -0
- package/src/utils/varint-encoder.ts +18 -0
- package/src/want-list.ts +529 -0
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
/* eslint-disable import/export */
|
|
2
|
+
/* eslint-disable complexity */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-namespace */
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */
|
|
5
|
+
/* eslint-disable @typescript-eslint/no-empty-interface */
|
|
6
|
+
|
|
7
|
+
import { type Codec, decodeMessage, encodeMessage, enumeration, message } from 'protons-runtime'
|
|
8
|
+
import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc'
|
|
9
|
+
import type { Uint8ArrayList } from 'uint8arraylist'
|
|
10
|
+
|
|
11
|
+
export enum WantType {
|
|
12
|
+
WantBlock = 'WantBlock',
|
|
13
|
+
WantHave = 'WantHave'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
enum __WantTypeValues {
|
|
17
|
+
WantBlock = 0,
|
|
18
|
+
WantHave = 1
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export namespace WantType {
|
|
22
|
+
export const codec = (): Codec<WantType> => {
|
|
23
|
+
return enumeration<WantType>(__WantTypeValues)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export interface WantlistEntry {
|
|
27
|
+
cid: Uint8Array
|
|
28
|
+
priority: number
|
|
29
|
+
cancel?: boolean
|
|
30
|
+
wantType?: WantType
|
|
31
|
+
sendDontHave?: boolean
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export namespace WantlistEntry {
|
|
35
|
+
let _codec: Codec<WantlistEntry>
|
|
36
|
+
|
|
37
|
+
export const codec = (): Codec<WantlistEntry> => {
|
|
38
|
+
if (_codec == null) {
|
|
39
|
+
_codec = message<WantlistEntry>((obj, w, opts = {}) => {
|
|
40
|
+
if (opts.lengthDelimited !== false) {
|
|
41
|
+
w.fork()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if ((obj.cid != null && obj.cid.byteLength > 0)) {
|
|
45
|
+
w.uint32(10)
|
|
46
|
+
w.bytes(obj.cid)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if ((obj.priority != null && obj.priority !== 0)) {
|
|
50
|
+
w.uint32(16)
|
|
51
|
+
w.int32(obj.priority)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (obj.cancel != null) {
|
|
55
|
+
w.uint32(24)
|
|
56
|
+
w.bool(obj.cancel)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (obj.wantType != null) {
|
|
60
|
+
w.uint32(32)
|
|
61
|
+
WantType.codec().encode(obj.wantType, w)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (obj.sendDontHave != null) {
|
|
65
|
+
w.uint32(40)
|
|
66
|
+
w.bool(obj.sendDontHave)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (opts.lengthDelimited !== false) {
|
|
70
|
+
w.ldelim()
|
|
71
|
+
}
|
|
72
|
+
}, (reader, length) => {
|
|
73
|
+
const obj: any = {
|
|
74
|
+
cid: uint8ArrayAlloc(0),
|
|
75
|
+
priority: 0
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const end = length == null ? reader.len : reader.pos + length
|
|
79
|
+
|
|
80
|
+
while (reader.pos < end) {
|
|
81
|
+
const tag = reader.uint32()
|
|
82
|
+
|
|
83
|
+
switch (tag >>> 3) {
|
|
84
|
+
case 1: {
|
|
85
|
+
obj.cid = reader.bytes()
|
|
86
|
+
break
|
|
87
|
+
}
|
|
88
|
+
case 2: {
|
|
89
|
+
obj.priority = reader.int32()
|
|
90
|
+
break
|
|
91
|
+
}
|
|
92
|
+
case 3: {
|
|
93
|
+
obj.cancel = reader.bool()
|
|
94
|
+
break
|
|
95
|
+
}
|
|
96
|
+
case 4: {
|
|
97
|
+
obj.wantType = WantType.codec().decode(reader)
|
|
98
|
+
break
|
|
99
|
+
}
|
|
100
|
+
case 5: {
|
|
101
|
+
obj.sendDontHave = reader.bool()
|
|
102
|
+
break
|
|
103
|
+
}
|
|
104
|
+
default: {
|
|
105
|
+
reader.skipType(tag & 7)
|
|
106
|
+
break
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return obj
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return _codec
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export const encode = (obj: Partial<WantlistEntry>): Uint8Array => {
|
|
119
|
+
return encodeMessage(obj, WantlistEntry.codec())
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export const decode = (buf: Uint8Array | Uint8ArrayList): WantlistEntry => {
|
|
123
|
+
return decodeMessage(buf, WantlistEntry.codec())
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface Wantlist {
|
|
128
|
+
entries: WantlistEntry[]
|
|
129
|
+
full?: boolean
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export namespace Wantlist {
|
|
133
|
+
let _codec: Codec<Wantlist>
|
|
134
|
+
|
|
135
|
+
export const codec = (): Codec<Wantlist> => {
|
|
136
|
+
if (_codec == null) {
|
|
137
|
+
_codec = message<Wantlist>((obj, w, opts = {}) => {
|
|
138
|
+
if (opts.lengthDelimited !== false) {
|
|
139
|
+
w.fork()
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (obj.entries != null) {
|
|
143
|
+
for (const value of obj.entries) {
|
|
144
|
+
w.uint32(10)
|
|
145
|
+
WantlistEntry.codec().encode(value, w)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (obj.full != null) {
|
|
150
|
+
w.uint32(16)
|
|
151
|
+
w.bool(obj.full)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (opts.lengthDelimited !== false) {
|
|
155
|
+
w.ldelim()
|
|
156
|
+
}
|
|
157
|
+
}, (reader, length) => {
|
|
158
|
+
const obj: any = {
|
|
159
|
+
entries: []
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const end = length == null ? reader.len : reader.pos + length
|
|
163
|
+
|
|
164
|
+
while (reader.pos < end) {
|
|
165
|
+
const tag = reader.uint32()
|
|
166
|
+
|
|
167
|
+
switch (tag >>> 3) {
|
|
168
|
+
case 1: {
|
|
169
|
+
obj.entries.push(WantlistEntry.codec().decode(reader, reader.uint32()))
|
|
170
|
+
break
|
|
171
|
+
}
|
|
172
|
+
case 2: {
|
|
173
|
+
obj.full = reader.bool()
|
|
174
|
+
break
|
|
175
|
+
}
|
|
176
|
+
default: {
|
|
177
|
+
reader.skipType(tag & 7)
|
|
178
|
+
break
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return obj
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return _codec
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export const encode = (obj: Partial<Wantlist>): Uint8Array => {
|
|
191
|
+
return encodeMessage(obj, Wantlist.codec())
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export const decode = (buf: Uint8Array | Uint8ArrayList): Wantlist => {
|
|
195
|
+
return decodeMessage(buf, Wantlist.codec())
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export interface Block {
|
|
200
|
+
prefix: Uint8Array
|
|
201
|
+
data: Uint8Array
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export namespace Block {
|
|
205
|
+
let _codec: Codec<Block>
|
|
206
|
+
|
|
207
|
+
export const codec = (): Codec<Block> => {
|
|
208
|
+
if (_codec == null) {
|
|
209
|
+
_codec = message<Block>((obj, w, opts = {}) => {
|
|
210
|
+
if (opts.lengthDelimited !== false) {
|
|
211
|
+
w.fork()
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if ((obj.prefix != null && obj.prefix.byteLength > 0)) {
|
|
215
|
+
w.uint32(10)
|
|
216
|
+
w.bytes(obj.prefix)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if ((obj.data != null && obj.data.byteLength > 0)) {
|
|
220
|
+
w.uint32(18)
|
|
221
|
+
w.bytes(obj.data)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (opts.lengthDelimited !== false) {
|
|
225
|
+
w.ldelim()
|
|
226
|
+
}
|
|
227
|
+
}, (reader, length) => {
|
|
228
|
+
const obj: any = {
|
|
229
|
+
prefix: uint8ArrayAlloc(0),
|
|
230
|
+
data: uint8ArrayAlloc(0)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const end = length == null ? reader.len : reader.pos + length
|
|
234
|
+
|
|
235
|
+
while (reader.pos < end) {
|
|
236
|
+
const tag = reader.uint32()
|
|
237
|
+
|
|
238
|
+
switch (tag >>> 3) {
|
|
239
|
+
case 1: {
|
|
240
|
+
obj.prefix = reader.bytes()
|
|
241
|
+
break
|
|
242
|
+
}
|
|
243
|
+
case 2: {
|
|
244
|
+
obj.data = reader.bytes()
|
|
245
|
+
break
|
|
246
|
+
}
|
|
247
|
+
default: {
|
|
248
|
+
reader.skipType(tag & 7)
|
|
249
|
+
break
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return obj
|
|
255
|
+
})
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return _codec
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export const encode = (obj: Partial<Block>): Uint8Array => {
|
|
262
|
+
return encodeMessage(obj, Block.codec())
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export const decode = (buf: Uint8Array | Uint8ArrayList): Block => {
|
|
266
|
+
return decodeMessage(buf, Block.codec())
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export enum BlockPresenceType {
|
|
271
|
+
HaveBlock = 'HaveBlock',
|
|
272
|
+
DontHaveBlock = 'DontHaveBlock'
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
enum __BlockPresenceTypeValues {
|
|
276
|
+
HaveBlock = 0,
|
|
277
|
+
DontHaveBlock = 1
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export namespace BlockPresenceType {
|
|
281
|
+
export const codec = (): Codec<BlockPresenceType> => {
|
|
282
|
+
return enumeration<BlockPresenceType>(__BlockPresenceTypeValues)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
export interface BlockPresence {
|
|
286
|
+
cid: Uint8Array
|
|
287
|
+
type: BlockPresenceType
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export namespace BlockPresence {
|
|
291
|
+
let _codec: Codec<BlockPresence>
|
|
292
|
+
|
|
293
|
+
export const codec = (): Codec<BlockPresence> => {
|
|
294
|
+
if (_codec == null) {
|
|
295
|
+
_codec = message<BlockPresence>((obj, w, opts = {}) => {
|
|
296
|
+
if (opts.lengthDelimited !== false) {
|
|
297
|
+
w.fork()
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if ((obj.cid != null && obj.cid.byteLength > 0)) {
|
|
301
|
+
w.uint32(10)
|
|
302
|
+
w.bytes(obj.cid)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (obj.type != null && __BlockPresenceTypeValues[obj.type] !== 0) {
|
|
306
|
+
w.uint32(16)
|
|
307
|
+
BlockPresenceType.codec().encode(obj.type, w)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (opts.lengthDelimited !== false) {
|
|
311
|
+
w.ldelim()
|
|
312
|
+
}
|
|
313
|
+
}, (reader, length) => {
|
|
314
|
+
const obj: any = {
|
|
315
|
+
cid: uint8ArrayAlloc(0),
|
|
316
|
+
type: BlockPresenceType.HaveBlock
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const end = length == null ? reader.len : reader.pos + length
|
|
320
|
+
|
|
321
|
+
while (reader.pos < end) {
|
|
322
|
+
const tag = reader.uint32()
|
|
323
|
+
|
|
324
|
+
switch (tag >>> 3) {
|
|
325
|
+
case 1: {
|
|
326
|
+
obj.cid = reader.bytes()
|
|
327
|
+
break
|
|
328
|
+
}
|
|
329
|
+
case 2: {
|
|
330
|
+
obj.type = BlockPresenceType.codec().decode(reader)
|
|
331
|
+
break
|
|
332
|
+
}
|
|
333
|
+
default: {
|
|
334
|
+
reader.skipType(tag & 7)
|
|
335
|
+
break
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return obj
|
|
341
|
+
})
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return _codec
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export const encode = (obj: Partial<BlockPresence>): Uint8Array => {
|
|
348
|
+
return encodeMessage(obj, BlockPresence.codec())
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export const decode = (buf: Uint8Array | Uint8ArrayList): BlockPresence => {
|
|
352
|
+
return decodeMessage(buf, BlockPresence.codec())
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export interface BitswapMessage {
|
|
357
|
+
wantlist?: Wantlist
|
|
358
|
+
blocks: Block[]
|
|
359
|
+
blockPresences: BlockPresence[]
|
|
360
|
+
pendingBytes: number
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export namespace BitswapMessage {
|
|
364
|
+
let _codec: Codec<BitswapMessage>
|
|
365
|
+
|
|
366
|
+
export const codec = (): Codec<BitswapMessage> => {
|
|
367
|
+
if (_codec == null) {
|
|
368
|
+
_codec = message<BitswapMessage>((obj, w, opts = {}) => {
|
|
369
|
+
if (opts.lengthDelimited !== false) {
|
|
370
|
+
w.fork()
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (obj.wantlist != null) {
|
|
374
|
+
w.uint32(10)
|
|
375
|
+
Wantlist.codec().encode(obj.wantlist, w)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (obj.blocks != null) {
|
|
379
|
+
for (const value of obj.blocks) {
|
|
380
|
+
w.uint32(26)
|
|
381
|
+
Block.codec().encode(value, w)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (obj.blockPresences != null) {
|
|
386
|
+
for (const value of obj.blockPresences) {
|
|
387
|
+
w.uint32(34)
|
|
388
|
+
BlockPresence.codec().encode(value, w)
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if ((obj.pendingBytes != null && obj.pendingBytes !== 0)) {
|
|
393
|
+
w.uint32(40)
|
|
394
|
+
w.int32(obj.pendingBytes)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (opts.lengthDelimited !== false) {
|
|
398
|
+
w.ldelim()
|
|
399
|
+
}
|
|
400
|
+
}, (reader, length) => {
|
|
401
|
+
const obj: any = {
|
|
402
|
+
blocks: [],
|
|
403
|
+
blockPresences: [],
|
|
404
|
+
pendingBytes: 0
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const end = length == null ? reader.len : reader.pos + length
|
|
408
|
+
|
|
409
|
+
while (reader.pos < end) {
|
|
410
|
+
const tag = reader.uint32()
|
|
411
|
+
|
|
412
|
+
switch (tag >>> 3) {
|
|
413
|
+
case 1: {
|
|
414
|
+
obj.wantlist = Wantlist.codec().decode(reader, reader.uint32())
|
|
415
|
+
break
|
|
416
|
+
}
|
|
417
|
+
case 3: {
|
|
418
|
+
obj.blocks.push(Block.codec().decode(reader, reader.uint32()))
|
|
419
|
+
break
|
|
420
|
+
}
|
|
421
|
+
case 4: {
|
|
422
|
+
obj.blockPresences.push(BlockPresence.codec().decode(reader, reader.uint32()))
|
|
423
|
+
break
|
|
424
|
+
}
|
|
425
|
+
case 5: {
|
|
426
|
+
obj.pendingBytes = reader.int32()
|
|
427
|
+
break
|
|
428
|
+
}
|
|
429
|
+
default: {
|
|
430
|
+
reader.skipType(tag & 7)
|
|
431
|
+
break
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return obj
|
|
437
|
+
})
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
return _codec
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export const encode = (obj: Partial<BitswapMessage>): Uint8Array => {
|
|
444
|
+
return encodeMessage(obj, BitswapMessage.codec())
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
export const decode = (buf: Uint8Array | Uint8ArrayList): BitswapMessage => {
|
|
448
|
+
return decodeMessage(buf, BitswapMessage.codec())
|
|
449
|
+
}
|
|
450
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { trackedPeerMap } from '@libp2p/peer-collections'
|
|
2
|
+
import { CID } from 'multiformats/cid'
|
|
3
|
+
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|
4
|
+
import { WantType } from '../pb/message.js'
|
|
5
|
+
import { Ledger } from './ledger.js'
|
|
6
|
+
import type { BitswapNotifyProgressEvents, WantListEntry } from '../index.js'
|
|
7
|
+
import type { Network } from '../network.js'
|
|
8
|
+
import type { BitswapMessage } from '../pb/message.js'
|
|
9
|
+
import type { ComponentLogger, Logger, Metrics, PeerId } from '@libp2p/interface'
|
|
10
|
+
import type { PeerMap } from '@libp2p/peer-collections'
|
|
11
|
+
import type { Blockstore } from 'interface-blockstore'
|
|
12
|
+
import type { AbortOptions } from 'it-length-prefixed-stream'
|
|
13
|
+
import type { ProgressOptions } from 'progress-events'
|
|
14
|
+
|
|
15
|
+
export interface PeerWantListsInit {
|
|
16
|
+
maxSizeReplaceHasWithBlock?: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface PeerWantListsComponents {
|
|
20
|
+
blockstore: Blockstore
|
|
21
|
+
network: Network
|
|
22
|
+
metrics?: Metrics
|
|
23
|
+
logger: ComponentLogger
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface PeerLedger {
|
|
27
|
+
peer: PeerId
|
|
28
|
+
value: number
|
|
29
|
+
sent: number
|
|
30
|
+
received: number
|
|
31
|
+
exchanged: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class PeerWantLists {
|
|
35
|
+
public blockstore: Blockstore
|
|
36
|
+
public network: Network
|
|
37
|
+
public readonly ledgerMap: PeerMap<Ledger>
|
|
38
|
+
private readonly maxSizeReplaceHasWithBlock?: number
|
|
39
|
+
private readonly log: Logger
|
|
40
|
+
|
|
41
|
+
constructor (components: PeerWantListsComponents, init: PeerWantListsInit = {}) {
|
|
42
|
+
this.blockstore = components.blockstore
|
|
43
|
+
this.network = components.network
|
|
44
|
+
this.maxSizeReplaceHasWithBlock = init.maxSizeReplaceHasWithBlock
|
|
45
|
+
this.log = components.logger.forComponent('helia:bitswap:peer-want-lists')
|
|
46
|
+
|
|
47
|
+
this.ledgerMap = trackedPeerMap({
|
|
48
|
+
name: 'ipfs_bitswap_ledger_map',
|
|
49
|
+
metrics: components.metrics
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
this.network.addEventListener('bitswap:message', (evt) => {
|
|
53
|
+
this.receiveMessage(evt.detail.peer, evt.detail.message)
|
|
54
|
+
.catch(err => {
|
|
55
|
+
this.log.error('error receiving bitswap message from %p', evt.detail.peer, err)
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
this.network.addEventListener('peer:disconnected', evt => {
|
|
59
|
+
this.peerDisconnected(evt.detail)
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
ledgerForPeer (peerId: PeerId): PeerLedger | undefined {
|
|
64
|
+
const ledger = this.ledgerMap.get(peerId)
|
|
65
|
+
|
|
66
|
+
if (ledger == null) {
|
|
67
|
+
return undefined
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
peer: ledger.peerId,
|
|
72
|
+
value: ledger.debtRatio(),
|
|
73
|
+
sent: ledger.bytesSent,
|
|
74
|
+
received: ledger.bytesReceived,
|
|
75
|
+
exchanged: ledger.exchangeCount
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
wantListForPeer (peerId: PeerId): WantListEntry[] | undefined {
|
|
80
|
+
const ledger = this.ledgerMap.get(peerId)
|
|
81
|
+
|
|
82
|
+
if (ledger == null) {
|
|
83
|
+
return undefined
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return [...ledger.wants.values()]
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
peers (): PeerId[] {
|
|
90
|
+
return Array.from(this.ledgerMap.values()).map((l) => l.peerId)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Handle incoming messages
|
|
95
|
+
*/
|
|
96
|
+
async receiveMessage (peerId: PeerId, message: BitswapMessage): Promise<void> {
|
|
97
|
+
let ledger = this.ledgerMap.get(peerId)
|
|
98
|
+
|
|
99
|
+
if (ledger == null) {
|
|
100
|
+
ledger = new Ledger({
|
|
101
|
+
peerId,
|
|
102
|
+
blockstore: this.blockstore,
|
|
103
|
+
network: this.network
|
|
104
|
+
}, {
|
|
105
|
+
maxSizeReplaceHasWithBlock: this.maxSizeReplaceHasWithBlock
|
|
106
|
+
})
|
|
107
|
+
this.ledgerMap.set(peerId, ledger)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// record the amount of block data received
|
|
111
|
+
ledger.receivedBytes(message.blocks?.reduce((acc, curr) => acc + curr.data.byteLength, 0) ?? 0)
|
|
112
|
+
|
|
113
|
+
if (message.wantlist != null) {
|
|
114
|
+
// if the message has a full wantlist, clear the current wantlist
|
|
115
|
+
if (message.wantlist.full === true) {
|
|
116
|
+
ledger.wants.clear()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// clear cancelled wants and add new wants to the ledger
|
|
120
|
+
for (const entry of message.wantlist.entries) {
|
|
121
|
+
const cid = CID.decode(entry.cid)
|
|
122
|
+
const cidStr = uint8ArrayToString(cid.multihash.bytes, 'base64')
|
|
123
|
+
|
|
124
|
+
if (entry.cancel === true) {
|
|
125
|
+
this.log('peer %p cancelled want of block for %c', peerId, cid)
|
|
126
|
+
ledger.wants.delete(cidStr)
|
|
127
|
+
} else {
|
|
128
|
+
if (entry.wantType === WantType.WantHave) {
|
|
129
|
+
this.log('peer %p wanted block presence for %c', peerId, cid)
|
|
130
|
+
} else {
|
|
131
|
+
this.log('peer %p wanted block for %c', peerId, cid)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
ledger.wants.set(cidStr, {
|
|
135
|
+
cid,
|
|
136
|
+
priority: entry.priority,
|
|
137
|
+
wantType: entry.wantType ?? WantType.WantBlock,
|
|
138
|
+
sendDontHave: entry.sendDontHave ?? false
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
await ledger.sendBlocksToPeer()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async receivedBlock (cid: CID, options: ProgressOptions<BitswapNotifyProgressEvents> & AbortOptions): Promise<void> {
|
|
148
|
+
const cidStr = uint8ArrayToString(cid.multihash.bytes, 'base64')
|
|
149
|
+
const ledgers: Ledger[] = []
|
|
150
|
+
|
|
151
|
+
for (const ledger of this.ledgerMap.values()) {
|
|
152
|
+
if (ledger.wants.has(cidStr)) {
|
|
153
|
+
ledgers.push(ledger)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
await Promise.all(
|
|
158
|
+
ledgers.map(async (ledger) => ledger.sendBlocksToPeer(options))
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
peerDisconnected (peerId: PeerId): void {
|
|
163
|
+
this.ledgerMap.delete(peerId)
|
|
164
|
+
}
|
|
165
|
+
}
|