@peerbit/pubsub 5.2.10 → 5.3.0
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/dist/benchmark/fanout-tree-parent-upgrade-default-ready.d.ts +3 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-default-ready.d.ts.map +1 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-default-ready.js +90 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-default-ready.js.map +1 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-eval.d.ts +2 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-eval.d.ts.map +1 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-eval.js +712 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-eval.js.map +1 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-multi-eval.d.ts +2 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-multi-eval.d.ts.map +1 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-multi-eval.js +1591 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-multi-eval.js.map +1 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-prepush.d.ts +2 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-prepush.d.ts.map +1 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-prepush.js +297 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-prepush.js.map +1 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-preset.d.ts +73 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-preset.d.ts.map +1 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-preset.js +183 -0
- package/dist/benchmark/fanout-tree-parent-upgrade-preset.js.map +1 -0
- package/dist/benchmark/fanout-tree-sim-lib.d.ts +101 -0
- package/dist/benchmark/fanout-tree-sim-lib.d.ts.map +1 -1
- package/dist/benchmark/fanout-tree-sim-lib.js +540 -38
- package/dist/benchmark/fanout-tree-sim-lib.js.map +1 -1
- package/dist/benchmark/fanout-tree-sim.d.ts +0 -9
- package/dist/benchmark/fanout-tree-sim.d.ts.map +1 -1
- package/dist/benchmark/fanout-tree-sim.js +369 -28
- package/dist/benchmark/fanout-tree-sim.js.map +1 -1
- package/dist/benchmark/index.js +20 -0
- package/dist/benchmark/index.js.map +1 -1
- package/dist/benchmark/pubsub-topic-sim-lib.d.ts +4 -0
- package/dist/benchmark/pubsub-topic-sim-lib.d.ts.map +1 -1
- package/dist/benchmark/pubsub-topic-sim-lib.js +58 -3
- package/dist/benchmark/pubsub-topic-sim-lib.js.map +1 -1
- package/dist/benchmark/pubsub-topic-sim.js +18 -0
- package/dist/benchmark/pubsub-topic-sim.js.map +1 -1
- package/dist/src/debounced-set.d.ts +1 -1
- package/dist/src/debounced-set.d.ts.map +1 -1
- package/dist/src/debounced-set.js +5 -1
- package/dist/src/debounced-set.js.map +1 -1
- package/dist/src/fanout-tree-codec.d.ts +330 -0
- package/dist/src/fanout-tree-codec.d.ts.map +1 -0
- package/dist/src/fanout-tree-codec.js +1209 -0
- package/dist/src/fanout-tree-codec.js.map +1 -0
- package/dist/src/fanout-tree-parent-upgrade.d.ts +117 -0
- package/dist/src/fanout-tree-parent-upgrade.d.ts.map +1 -0
- package/dist/src/fanout-tree-parent-upgrade.js +135 -0
- package/dist/src/fanout-tree-parent-upgrade.js.map +1 -0
- package/dist/src/fanout-tree.d.ts +241 -73
- package/dist/src/fanout-tree.d.ts.map +1 -1
- package/dist/src/fanout-tree.js +2224 -1050
- package/dist/src/fanout-tree.js.map +1 -1
- package/dist/src/index.d.ts +57 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +293 -41
- package/dist/src/index.js.map +1 -1
- package/dist/src/topic-root-control-plane.d.ts +13 -0
- package/dist/src/topic-root-control-plane.d.ts.map +1 -1
- package/dist/src/topic-root-control-plane.js +45 -0
- package/dist/src/topic-root-control-plane.js.map +1 -1
- package/package.json +6 -6
- package/src/debounced-set.ts +5 -0
- package/src/fanout-tree-codec.ts +1580 -0
- package/src/fanout-tree-parent-upgrade.ts +353 -0
- package/src/fanout-tree.ts +4467 -2204
- package/src/index.ts +392 -56
- package/src/topic-root-control-plane.ts +48 -0
|
@@ -0,0 +1,1209 @@
|
|
|
1
|
+
import { multiaddr } from "@multiformats/multiaddr";
|
|
2
|
+
export const JOIN_REJECT_REDIRECT_MAX = 4;
|
|
3
|
+
export const JOIN_REJECT_REDIRECT_ADDR_MAX = 8;
|
|
4
|
+
export const MSG_JOIN_REQ = 1;
|
|
5
|
+
export const MSG_JOIN_ACCEPT = 2;
|
|
6
|
+
export const MSG_JOIN_REJECT = 3;
|
|
7
|
+
export const MSG_KICK = 4;
|
|
8
|
+
export const MSG_DATA = 10;
|
|
9
|
+
export const MSG_END = 11;
|
|
10
|
+
export const MSG_UNICAST = 12;
|
|
11
|
+
export const MSG_ROUTE_QUERY = 13;
|
|
12
|
+
export const MSG_ROUTE_REPLY = 14;
|
|
13
|
+
export const MSG_PUBLISH_PROXY = 15;
|
|
14
|
+
export const MSG_LEAVE = 16;
|
|
15
|
+
export const MSG_UNICAST_ACK = 17;
|
|
16
|
+
export const MSG_REPAIR_REQ = 20;
|
|
17
|
+
export const MSG_FETCH_REQ = 21;
|
|
18
|
+
export const MSG_IHAVE = 22;
|
|
19
|
+
export const MSG_TRACKER_ANNOUNCE = 30;
|
|
20
|
+
export const MSG_TRACKER_QUERY = 31;
|
|
21
|
+
export const MSG_TRACKER_REPLY = 32;
|
|
22
|
+
export const MSG_TRACKER_FEEDBACK = 33;
|
|
23
|
+
export const MSG_PROVIDER_ANNOUNCE = 34;
|
|
24
|
+
export const MSG_PROVIDER_QUERY = 35;
|
|
25
|
+
export const MSG_PROVIDER_REPLY = 36;
|
|
26
|
+
export const MSG_PROVIDER_SUBSCRIBE = 37;
|
|
27
|
+
export const MSG_PROVIDER_UNSUBSCRIBE = 38;
|
|
28
|
+
export const MSG_PROVIDER_NOTIFY = 39;
|
|
29
|
+
export const MSG_PARENT_PROBE_REQ = 40;
|
|
30
|
+
export const MSG_PARENT_PROBE_REPLY = 41;
|
|
31
|
+
export const JOIN_REJECT_NOT_ATTACHED = 1;
|
|
32
|
+
export const JOIN_REJECT_NO_CAPACITY = 2;
|
|
33
|
+
export const JOIN_REJECT_LOW_BID = 3;
|
|
34
|
+
export const TRACKER_FEEDBACK_JOINED = 1;
|
|
35
|
+
export const TRACKER_FEEDBACK_DIAL_FAILED = 2;
|
|
36
|
+
export const TRACKER_FEEDBACK_JOIN_TIMEOUT = 3;
|
|
37
|
+
export const TRACKER_FEEDBACK_JOIN_REJECT = 4;
|
|
38
|
+
export const PARENT_PROBE_FLAG_ROOTED = 1 << 0;
|
|
39
|
+
export const PARENT_PROBE_FLAG_ACCEPTING = 1 << 1;
|
|
40
|
+
export const PARENT_PROBE_FLAG_REPAIRING = 1 << 2;
|
|
41
|
+
export const PARENT_PROBE_FLAG_OVERLOADED = 1 << 3;
|
|
42
|
+
export const UNICAST_FLAG_ACK = 1;
|
|
43
|
+
export const UNICAST_ACK_DEFAULT_TIMEOUT_MS = 30_000;
|
|
44
|
+
const PARENT_PROBE_REQ_FLAG_RESERVE_ROOT = 1 << 0;
|
|
45
|
+
export const MAX_ROUTE_HOPS = 32;
|
|
46
|
+
const textEncoder = new TextEncoder();
|
|
47
|
+
const textDecoder = new TextDecoder();
|
|
48
|
+
export const clampU16 = (v) => Math.max(0, Math.min(0xffff, v | 0));
|
|
49
|
+
export const writeU32BE = (buf, offset, value) => {
|
|
50
|
+
buf[offset + 0] = (value >>> 24) & 0xff;
|
|
51
|
+
buf[offset + 1] = (value >>> 16) & 0xff;
|
|
52
|
+
buf[offset + 2] = (value >>> 8) & 0xff;
|
|
53
|
+
buf[offset + 3] = value & 0xff;
|
|
54
|
+
};
|
|
55
|
+
export const readU32BE = (buf, offset) => ((buf[offset + 0] << 24) |
|
|
56
|
+
(buf[offset + 1] << 16) |
|
|
57
|
+
(buf[offset + 2] << 8) |
|
|
58
|
+
buf[offset + 3]) >>>
|
|
59
|
+
0;
|
|
60
|
+
const writeU64BE = (buf, offset, value) => {
|
|
61
|
+
let v = value & 0xffffffffffffffffn;
|
|
62
|
+
for (let i = 7; i >= 0; i--) {
|
|
63
|
+
buf[offset + i] = Number(v & 0xffn);
|
|
64
|
+
v >>= 8n;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
export const readU64BE = (buf, offset) => {
|
|
68
|
+
let v = 0n;
|
|
69
|
+
for (let i = 0; i < 8; i++) {
|
|
70
|
+
v = (v << 8n) | BigInt(buf[offset + i]);
|
|
71
|
+
}
|
|
72
|
+
return v;
|
|
73
|
+
};
|
|
74
|
+
export const writeU16BE = (buf, offset, value) => {
|
|
75
|
+
buf[offset + 0] = (value >>> 8) & 0xff;
|
|
76
|
+
buf[offset + 1] = value & 0xff;
|
|
77
|
+
};
|
|
78
|
+
export const readU16BE = (buf, offset) => ((buf[offset + 0] << 8) | buf[offset + 1]) >>> 0;
|
|
79
|
+
const CONTROL_FRAME_CHANNEL_KEY_BYTES = 32;
|
|
80
|
+
const CONTROL_FRAME_HEADER_BYTES = 1 + CONTROL_FRAME_CHANNEL_KEY_BYTES;
|
|
81
|
+
class FrameWriter {
|
|
82
|
+
buf;
|
|
83
|
+
offset = 0;
|
|
84
|
+
constructor(kind, channelKey, payloadBytes) {
|
|
85
|
+
this.buf = new Uint8Array(CONTROL_FRAME_HEADER_BYTES + payloadBytes);
|
|
86
|
+
this.u8(kind);
|
|
87
|
+
this.bytes(channelKey, CONTROL_FRAME_CHANNEL_KEY_BYTES, "channel key");
|
|
88
|
+
}
|
|
89
|
+
ensure(bytes) {
|
|
90
|
+
if (this.offset + bytes > this.buf.length) {
|
|
91
|
+
throw new Error("control frame write overflow");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
u8(value) {
|
|
95
|
+
this.ensure(1);
|
|
96
|
+
this.buf[this.offset++] = value & 0xff;
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
u16(value) {
|
|
100
|
+
this.ensure(2);
|
|
101
|
+
writeU16BE(this.buf, this.offset, value);
|
|
102
|
+
this.offset += 2;
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
u32(value) {
|
|
106
|
+
this.ensure(4);
|
|
107
|
+
writeU32BE(this.buf, this.offset, value);
|
|
108
|
+
this.offset += 4;
|
|
109
|
+
return this;
|
|
110
|
+
}
|
|
111
|
+
bytes(value, expectedLength = value.length, label = "bytes") {
|
|
112
|
+
if (value.length !== expectedLength) {
|
|
113
|
+
throw new Error(`invalid ${label} length: expected ${expectedLength}, got ${value.length}`);
|
|
114
|
+
}
|
|
115
|
+
this.ensure(value.length);
|
|
116
|
+
this.buf.set(value, this.offset);
|
|
117
|
+
this.offset += value.length;
|
|
118
|
+
return this;
|
|
119
|
+
}
|
|
120
|
+
done() {
|
|
121
|
+
if (this.offset !== this.buf.length) {
|
|
122
|
+
throw new Error("control frame write underflow");
|
|
123
|
+
}
|
|
124
|
+
return this.buf;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
class FrameReader {
|
|
128
|
+
buf;
|
|
129
|
+
offset;
|
|
130
|
+
constructor(buf, offset) {
|
|
131
|
+
this.buf = buf;
|
|
132
|
+
this.offset = offset;
|
|
133
|
+
}
|
|
134
|
+
static control(data, minPayloadBytes) {
|
|
135
|
+
if (data.length < CONTROL_FRAME_HEADER_BYTES + minPayloadBytes) {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
return new FrameReader(data, CONTROL_FRAME_HEADER_BYTES);
|
|
139
|
+
}
|
|
140
|
+
remaining() {
|
|
141
|
+
return this.buf.length - this.offset;
|
|
142
|
+
}
|
|
143
|
+
has(bytes) {
|
|
144
|
+
return this.remaining() >= bytes;
|
|
145
|
+
}
|
|
146
|
+
u8() {
|
|
147
|
+
if (!this.has(1))
|
|
148
|
+
return undefined;
|
|
149
|
+
return this.buf[this.offset++];
|
|
150
|
+
}
|
|
151
|
+
u16() {
|
|
152
|
+
if (!this.has(2))
|
|
153
|
+
return undefined;
|
|
154
|
+
const value = readU16BE(this.buf, this.offset);
|
|
155
|
+
this.offset += 2;
|
|
156
|
+
return value;
|
|
157
|
+
}
|
|
158
|
+
u32() {
|
|
159
|
+
if (!this.has(4))
|
|
160
|
+
return undefined;
|
|
161
|
+
const value = readU32BE(this.buf, this.offset);
|
|
162
|
+
this.offset += 4;
|
|
163
|
+
return value;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const JOIN_REQ_PAYLOAD_BYTES = 4 + 4;
|
|
167
|
+
const JOIN_REQ_RESERVATION_BYTES = 4;
|
|
168
|
+
export const encodeJoinReq = (channelKey, reqId, bidPerByte, parentUpgradeReservationToken = 0) => {
|
|
169
|
+
const hasReservation = parentUpgradeReservationToken > 0;
|
|
170
|
+
const frame = new FrameWriter(MSG_JOIN_REQ, channelKey, JOIN_REQ_PAYLOAD_BYTES + (hasReservation ? JOIN_REQ_RESERVATION_BYTES : 0))
|
|
171
|
+
.u32(reqId >>> 0)
|
|
172
|
+
.u32(bidPerByte >>> 0);
|
|
173
|
+
if (hasReservation) {
|
|
174
|
+
frame.u32(parentUpgradeReservationToken >>> 0);
|
|
175
|
+
}
|
|
176
|
+
return frame.done();
|
|
177
|
+
};
|
|
178
|
+
export const decodeJoinReq = (data) => {
|
|
179
|
+
const frame = FrameReader.control(data, JOIN_REQ_PAYLOAD_BYTES);
|
|
180
|
+
if (!frame)
|
|
181
|
+
return undefined;
|
|
182
|
+
const reqId = frame.u32();
|
|
183
|
+
const bidPerByte = frame.u32();
|
|
184
|
+
if (reqId == null || bidPerByte == null)
|
|
185
|
+
return undefined;
|
|
186
|
+
return {
|
|
187
|
+
reqId,
|
|
188
|
+
bidPerByte,
|
|
189
|
+
parentUpgradeReservationToken: frame.has(JOIN_REQ_RESERVATION_BYTES)
|
|
190
|
+
? (frame.u32() ?? 0)
|
|
191
|
+
: 0,
|
|
192
|
+
};
|
|
193
|
+
};
|
|
194
|
+
export const encodeJoinAccept = (channelKey, reqId, level, parentRouteFromRoot, haveRange) => {
|
|
195
|
+
const routeBytes = [];
|
|
196
|
+
let bytes = 1 + 32 + 4 + 2 + 1;
|
|
197
|
+
if (haveRange)
|
|
198
|
+
bytes += 8;
|
|
199
|
+
let count = 0;
|
|
200
|
+
for (const hop of parentRouteFromRoot ?? []) {
|
|
201
|
+
if (count >= MAX_ROUTE_HOPS)
|
|
202
|
+
break;
|
|
203
|
+
if (typeof hop !== "string")
|
|
204
|
+
continue;
|
|
205
|
+
const hb = textEncoder.encode(hop);
|
|
206
|
+
if (hb.length === 0 || hb.length > 255)
|
|
207
|
+
continue;
|
|
208
|
+
routeBytes.push(hb);
|
|
209
|
+
bytes += 1 + hb.length;
|
|
210
|
+
count += 1;
|
|
211
|
+
}
|
|
212
|
+
const buf = new Uint8Array(bytes);
|
|
213
|
+
buf[0] = MSG_JOIN_ACCEPT;
|
|
214
|
+
buf.set(channelKey, 1);
|
|
215
|
+
writeU32BE(buf, 33, reqId >>> 0);
|
|
216
|
+
writeU16BE(buf, 37, level & 0xffff);
|
|
217
|
+
buf[39] = count & 0xff;
|
|
218
|
+
let offset = 40;
|
|
219
|
+
for (const hb of routeBytes) {
|
|
220
|
+
buf[offset++] = hb.length & 0xff;
|
|
221
|
+
buf.set(hb, offset);
|
|
222
|
+
offset += hb.length;
|
|
223
|
+
}
|
|
224
|
+
if (haveRange) {
|
|
225
|
+
writeU32BE(buf, offset, haveRange.haveFrom >>> 0);
|
|
226
|
+
offset += 4;
|
|
227
|
+
writeU32BE(buf, offset, haveRange.haveToExclusive >>> 0);
|
|
228
|
+
offset += 4;
|
|
229
|
+
}
|
|
230
|
+
return buf;
|
|
231
|
+
};
|
|
232
|
+
export const encodeJoinReject = (channelKey, reqId, reason, redirects) => {
|
|
233
|
+
const encoded = [];
|
|
234
|
+
for (const r of redirects ?? []) {
|
|
235
|
+
if (!r?.hash)
|
|
236
|
+
continue;
|
|
237
|
+
const hashBytes = textEncoder.encode(r.hash);
|
|
238
|
+
if (hashBytes.length === 0 || hashBytes.length > 255)
|
|
239
|
+
continue;
|
|
240
|
+
const addrs = (r.addrs ?? [])
|
|
241
|
+
.filter((a) => a instanceof Uint8Array)
|
|
242
|
+
.filter((a) => a.length > 0 && a.length <= 0xffff)
|
|
243
|
+
.slice(0, JOIN_REJECT_REDIRECT_ADDR_MAX);
|
|
244
|
+
if (addrs.length === 0)
|
|
245
|
+
continue;
|
|
246
|
+
encoded.push({ hashBytes, addrs });
|
|
247
|
+
if (encoded.length >= JOIN_REJECT_REDIRECT_MAX)
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
if (encoded.length === 0) {
|
|
251
|
+
const buf = new Uint8Array(1 + 32 + 4 + 1);
|
|
252
|
+
buf[0] = MSG_JOIN_REJECT;
|
|
253
|
+
buf.set(channelKey, 1);
|
|
254
|
+
writeU32BE(buf, 33, reqId >>> 0);
|
|
255
|
+
buf[37] = reason & 0xff;
|
|
256
|
+
return buf;
|
|
257
|
+
}
|
|
258
|
+
let bytes = 1 + 32 + 4 + 1 + 1;
|
|
259
|
+
for (const e of encoded) {
|
|
260
|
+
bytes += 1 + e.hashBytes.length + 1;
|
|
261
|
+
for (const a of e.addrs)
|
|
262
|
+
bytes += 2 + a.length;
|
|
263
|
+
}
|
|
264
|
+
const buf = new Uint8Array(bytes);
|
|
265
|
+
buf[0] = MSG_JOIN_REJECT;
|
|
266
|
+
buf.set(channelKey, 1);
|
|
267
|
+
writeU32BE(buf, 33, reqId >>> 0);
|
|
268
|
+
buf[37] = reason & 0xff;
|
|
269
|
+
buf[38] = Math.max(0, Math.min(255, encoded.length)) & 0xff;
|
|
270
|
+
let offset = 39;
|
|
271
|
+
for (const e of encoded) {
|
|
272
|
+
buf[offset++] = e.hashBytes.length & 0xff;
|
|
273
|
+
buf.set(e.hashBytes, offset);
|
|
274
|
+
offset += e.hashBytes.length;
|
|
275
|
+
buf[offset++] = Math.max(0, Math.min(255, e.addrs.length)) & 0xff;
|
|
276
|
+
for (const a of e.addrs) {
|
|
277
|
+
writeU16BE(buf, offset, a.length);
|
|
278
|
+
offset += 2;
|
|
279
|
+
buf.set(a, offset);
|
|
280
|
+
offset += a.length;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return buf;
|
|
284
|
+
};
|
|
285
|
+
export const encodeKick = (channelKey) => {
|
|
286
|
+
const buf = new Uint8Array(1 + 32);
|
|
287
|
+
buf[0] = MSG_KICK;
|
|
288
|
+
buf.set(channelKey, 1);
|
|
289
|
+
return buf;
|
|
290
|
+
};
|
|
291
|
+
export const encodeEnd = (channelKey, lastSeqExclusive) => {
|
|
292
|
+
const buf = new Uint8Array(1 + 32 + 4);
|
|
293
|
+
buf[0] = MSG_END;
|
|
294
|
+
buf.set(channelKey, 1);
|
|
295
|
+
writeU32BE(buf, 33, lastSeqExclusive >>> 0);
|
|
296
|
+
return buf;
|
|
297
|
+
};
|
|
298
|
+
export const encodeRepairReq = (channelKey, reqId, missingSeqs) => {
|
|
299
|
+
const count = Math.max(0, Math.min(255, missingSeqs.length));
|
|
300
|
+
const buf = new Uint8Array(1 + 32 + 4 + 1 + count * 4);
|
|
301
|
+
buf[0] = MSG_REPAIR_REQ;
|
|
302
|
+
buf.set(channelKey, 1);
|
|
303
|
+
writeU32BE(buf, 33, reqId >>> 0);
|
|
304
|
+
buf[37] = count & 0xff;
|
|
305
|
+
for (let i = 0; i < count; i++) {
|
|
306
|
+
writeU32BE(buf, 38 + i * 4, missingSeqs[i] >>> 0);
|
|
307
|
+
}
|
|
308
|
+
return buf;
|
|
309
|
+
};
|
|
310
|
+
export const encodeFetchReq = (channelKey, reqId, missingSeqs) => {
|
|
311
|
+
const count = Math.max(0, Math.min(255, missingSeqs.length));
|
|
312
|
+
const buf = new Uint8Array(1 + 32 + 4 + 1 + count * 4);
|
|
313
|
+
buf[0] = MSG_FETCH_REQ;
|
|
314
|
+
buf.set(channelKey, 1);
|
|
315
|
+
writeU32BE(buf, 33, reqId >>> 0);
|
|
316
|
+
buf[37] = count & 0xff;
|
|
317
|
+
for (let i = 0; i < count; i++) {
|
|
318
|
+
writeU32BE(buf, 38 + i * 4, missingSeqs[i] >>> 0);
|
|
319
|
+
}
|
|
320
|
+
return buf;
|
|
321
|
+
};
|
|
322
|
+
export const encodeIHave = (channelKey, haveFrom, haveToExclusive) => {
|
|
323
|
+
const buf = new Uint8Array(1 + 32 + 4 + 4);
|
|
324
|
+
buf[0] = MSG_IHAVE;
|
|
325
|
+
buf.set(channelKey, 1);
|
|
326
|
+
writeU32BE(buf, 33, haveFrom >>> 0);
|
|
327
|
+
writeU32BE(buf, 37, haveToExclusive >>> 0);
|
|
328
|
+
return buf;
|
|
329
|
+
};
|
|
330
|
+
export const encodeData = (payload) => {
|
|
331
|
+
const buf = new Uint8Array(1 + payload.length);
|
|
332
|
+
buf[0] = MSG_DATA;
|
|
333
|
+
buf.set(payload, 1);
|
|
334
|
+
return buf;
|
|
335
|
+
};
|
|
336
|
+
export const encodePublishProxy = (channelKey, payload) => {
|
|
337
|
+
const buf = new Uint8Array(1 + 32 + payload.length);
|
|
338
|
+
buf[0] = MSG_PUBLISH_PROXY;
|
|
339
|
+
buf.set(channelKey, 1);
|
|
340
|
+
buf.set(payload, 33);
|
|
341
|
+
return buf;
|
|
342
|
+
};
|
|
343
|
+
export const encodeLeave = (channelKey) => {
|
|
344
|
+
const buf = new Uint8Array(1 + 32);
|
|
345
|
+
buf[0] = MSG_LEAVE;
|
|
346
|
+
buf.set(channelKey, 1);
|
|
347
|
+
return buf;
|
|
348
|
+
};
|
|
349
|
+
export const encodeUnicast = (channelKey, route, payload, options) => {
|
|
350
|
+
const wantsAck = options?.ackToken != null;
|
|
351
|
+
const flags = wantsAck ? UNICAST_FLAG_ACK : 0;
|
|
352
|
+
const toRouteBytes = [];
|
|
353
|
+
let bytes = 1 + 32 + 1 + (wantsAck ? 8 : 0) + 1;
|
|
354
|
+
let toCount = 0;
|
|
355
|
+
for (const hop of route ?? []) {
|
|
356
|
+
if (toCount >= MAX_ROUTE_HOPS)
|
|
357
|
+
break;
|
|
358
|
+
if (typeof hop !== "string")
|
|
359
|
+
continue;
|
|
360
|
+
const hb = textEncoder.encode(hop);
|
|
361
|
+
if (hb.length === 0 || hb.length > 255)
|
|
362
|
+
continue;
|
|
363
|
+
toRouteBytes.push(hb);
|
|
364
|
+
bytes += 1 + hb.length;
|
|
365
|
+
toCount += 1;
|
|
366
|
+
}
|
|
367
|
+
const replyRouteBytes = [];
|
|
368
|
+
let replyCount = 0;
|
|
369
|
+
if (wantsAck) {
|
|
370
|
+
bytes += 1; // replyRouteCount
|
|
371
|
+
for (const hop of options?.replyRoute ?? []) {
|
|
372
|
+
if (replyCount >= MAX_ROUTE_HOPS)
|
|
373
|
+
break;
|
|
374
|
+
if (typeof hop !== "string")
|
|
375
|
+
continue;
|
|
376
|
+
const hb = textEncoder.encode(hop);
|
|
377
|
+
if (hb.length === 0 || hb.length > 255)
|
|
378
|
+
continue;
|
|
379
|
+
replyRouteBytes.push(hb);
|
|
380
|
+
bytes += 1 + hb.length;
|
|
381
|
+
replyCount += 1;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
bytes += payload.byteLength;
|
|
385
|
+
const buf = new Uint8Array(bytes);
|
|
386
|
+
buf[0] = MSG_UNICAST;
|
|
387
|
+
buf.set(channelKey, 1);
|
|
388
|
+
buf[33] = flags & 0xff;
|
|
389
|
+
let offset = 34;
|
|
390
|
+
if (wantsAck) {
|
|
391
|
+
writeU64BE(buf, offset, options.ackToken);
|
|
392
|
+
offset += 8;
|
|
393
|
+
}
|
|
394
|
+
buf[offset++] = toCount & 0xff;
|
|
395
|
+
for (const hb of toRouteBytes) {
|
|
396
|
+
buf[offset++] = hb.length & 0xff;
|
|
397
|
+
buf.set(hb, offset);
|
|
398
|
+
offset += hb.length;
|
|
399
|
+
}
|
|
400
|
+
if (wantsAck) {
|
|
401
|
+
buf[offset++] = replyCount & 0xff;
|
|
402
|
+
for (const hb of replyRouteBytes) {
|
|
403
|
+
buf[offset++] = hb.length & 0xff;
|
|
404
|
+
buf.set(hb, offset);
|
|
405
|
+
offset += hb.length;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
buf.set(payload, offset);
|
|
409
|
+
return buf;
|
|
410
|
+
};
|
|
411
|
+
export const encodeUnicastAck = (channelKey, ackToken, route) => {
|
|
412
|
+
const routeBytes = [];
|
|
413
|
+
let bytes = 1 + 32 + 8 + 1;
|
|
414
|
+
let count = 0;
|
|
415
|
+
for (const hop of route ?? []) {
|
|
416
|
+
if (count >= MAX_ROUTE_HOPS)
|
|
417
|
+
break;
|
|
418
|
+
if (typeof hop !== "string")
|
|
419
|
+
continue;
|
|
420
|
+
const hb = textEncoder.encode(hop);
|
|
421
|
+
if (hb.length === 0 || hb.length > 255)
|
|
422
|
+
continue;
|
|
423
|
+
routeBytes.push(hb);
|
|
424
|
+
bytes += 1 + hb.length;
|
|
425
|
+
count += 1;
|
|
426
|
+
}
|
|
427
|
+
const buf = new Uint8Array(bytes);
|
|
428
|
+
buf[0] = MSG_UNICAST_ACK;
|
|
429
|
+
buf.set(channelKey, 1);
|
|
430
|
+
writeU64BE(buf, 33, ackToken);
|
|
431
|
+
buf[41] = count & 0xff;
|
|
432
|
+
let offset = 42;
|
|
433
|
+
for (const hb of routeBytes) {
|
|
434
|
+
buf[offset++] = hb.length & 0xff;
|
|
435
|
+
buf.set(hb, offset);
|
|
436
|
+
offset += hb.length;
|
|
437
|
+
}
|
|
438
|
+
return buf;
|
|
439
|
+
};
|
|
440
|
+
export const encodeRouteQuery = (channelKey, reqId, targetHash) => {
|
|
441
|
+
const targetBytes = textEncoder.encode(targetHash);
|
|
442
|
+
const targetLen = Math.max(0, Math.min(255, targetBytes.length));
|
|
443
|
+
const buf = new Uint8Array(1 + 32 + 4 + 1 + targetLen);
|
|
444
|
+
buf[0] = MSG_ROUTE_QUERY;
|
|
445
|
+
buf.set(channelKey, 1);
|
|
446
|
+
writeU32BE(buf, 33, reqId >>> 0);
|
|
447
|
+
buf[37] = targetLen & 0xff;
|
|
448
|
+
buf.set(targetBytes.subarray(0, targetLen), 38);
|
|
449
|
+
return buf;
|
|
450
|
+
};
|
|
451
|
+
export const encodeRouteReply = (channelKey, reqId, route) => {
|
|
452
|
+
const routeBytes = [];
|
|
453
|
+
let bytes = 1 + 32 + 4 + 1;
|
|
454
|
+
let count = 0;
|
|
455
|
+
for (const hop of route ?? []) {
|
|
456
|
+
if (count >= MAX_ROUTE_HOPS)
|
|
457
|
+
break;
|
|
458
|
+
if (typeof hop !== "string")
|
|
459
|
+
continue;
|
|
460
|
+
const hb = textEncoder.encode(hop);
|
|
461
|
+
if (hb.length === 0 || hb.length > 255)
|
|
462
|
+
continue;
|
|
463
|
+
routeBytes.push(hb);
|
|
464
|
+
bytes += 1 + hb.length;
|
|
465
|
+
count += 1;
|
|
466
|
+
}
|
|
467
|
+
const buf = new Uint8Array(bytes);
|
|
468
|
+
buf[0] = MSG_ROUTE_REPLY;
|
|
469
|
+
buf.set(channelKey, 1);
|
|
470
|
+
writeU32BE(buf, 33, reqId >>> 0);
|
|
471
|
+
buf[37] = count & 0xff;
|
|
472
|
+
let offset = 38;
|
|
473
|
+
for (const hb of routeBytes) {
|
|
474
|
+
buf[offset++] = hb.length & 0xff;
|
|
475
|
+
buf.set(hb, offset);
|
|
476
|
+
offset += hb.length;
|
|
477
|
+
}
|
|
478
|
+
return buf;
|
|
479
|
+
};
|
|
480
|
+
export const decodeRoute = (data, offsetStart, routeCount) => {
|
|
481
|
+
let offset = offsetStart;
|
|
482
|
+
const route = [];
|
|
483
|
+
for (let i = 0; i < routeCount; i++) {
|
|
484
|
+
if (offset + 1 > data.length)
|
|
485
|
+
break;
|
|
486
|
+
const len = data[offset++];
|
|
487
|
+
if (len === 0)
|
|
488
|
+
break;
|
|
489
|
+
if (offset + len > data.length)
|
|
490
|
+
break;
|
|
491
|
+
if (route.length < MAX_ROUTE_HOPS) {
|
|
492
|
+
route.push(textDecoder.decode(data.subarray(offset, offset + len)));
|
|
493
|
+
}
|
|
494
|
+
offset += len;
|
|
495
|
+
}
|
|
496
|
+
return { route, offset };
|
|
497
|
+
};
|
|
498
|
+
export const encodeTrackerAnnounce = (channelKey, ttlMs, level, maxChildren, freeSlots, bidPerByte, addrs) => {
|
|
499
|
+
const addrCount = Math.max(0, Math.min(255, addrs.length));
|
|
500
|
+
let bytes = 1 + 32 + 4 + 2 + 2 + 2 + 4 + 1;
|
|
501
|
+
const addrBytes = new Array(addrCount);
|
|
502
|
+
for (let i = 0; i < addrCount; i++) {
|
|
503
|
+
const b = addrs[i].bytes;
|
|
504
|
+
addrBytes[i] = b;
|
|
505
|
+
bytes += 2 + b.length;
|
|
506
|
+
}
|
|
507
|
+
const buf = new Uint8Array(bytes);
|
|
508
|
+
buf[0] = MSG_TRACKER_ANNOUNCE;
|
|
509
|
+
buf.set(channelKey, 1);
|
|
510
|
+
writeU32BE(buf, 33, Math.max(0, Math.floor(ttlMs)) >>> 0);
|
|
511
|
+
writeU16BE(buf, 37, clampU16(level));
|
|
512
|
+
writeU16BE(buf, 39, clampU16(maxChildren));
|
|
513
|
+
writeU16BE(buf, 41, clampU16(freeSlots));
|
|
514
|
+
writeU32BE(buf, 43, Math.max(0, Math.floor(bidPerByte)) >>> 0);
|
|
515
|
+
buf[47] = addrCount & 0xff;
|
|
516
|
+
let offset = 48;
|
|
517
|
+
for (let i = 0; i < addrCount; i++) {
|
|
518
|
+
const b = addrBytes[i];
|
|
519
|
+
writeU16BE(buf, offset, b.length);
|
|
520
|
+
offset += 2;
|
|
521
|
+
buf.set(b, offset);
|
|
522
|
+
offset += b.length;
|
|
523
|
+
}
|
|
524
|
+
return buf;
|
|
525
|
+
};
|
|
526
|
+
export const encodeTrackerQuery = (channelKey, reqId, want) => {
|
|
527
|
+
const buf = new Uint8Array(1 + 32 + 4 + 2);
|
|
528
|
+
buf[0] = MSG_TRACKER_QUERY;
|
|
529
|
+
buf.set(channelKey, 1);
|
|
530
|
+
writeU32BE(buf, 33, reqId >>> 0);
|
|
531
|
+
writeU16BE(buf, 37, clampU16(want));
|
|
532
|
+
return buf;
|
|
533
|
+
};
|
|
534
|
+
export const encodeTrackerReply = (channelKey, reqId, entries) => {
|
|
535
|
+
const count = Math.max(0, Math.min(255, entries.length));
|
|
536
|
+
let bytes = 1 + 32 + 4 + 1;
|
|
537
|
+
const encoded = [];
|
|
538
|
+
for (let i = 0; i < count; i++) {
|
|
539
|
+
const e = entries[i];
|
|
540
|
+
const hashBytes = textEncoder.encode(e.hash);
|
|
541
|
+
if (hashBytes.length > 255)
|
|
542
|
+
continue;
|
|
543
|
+
const addrCount = Math.max(0, Math.min(255, e.addrs.length));
|
|
544
|
+
const addrs = e.addrs.slice(0, addrCount);
|
|
545
|
+
bytes += 1 + hashBytes.length + 2 + 2 + 4 + 1;
|
|
546
|
+
for (const a of addrs)
|
|
547
|
+
bytes += 2 + a.length;
|
|
548
|
+
encoded.push({
|
|
549
|
+
hashBytes,
|
|
550
|
+
level: e.level,
|
|
551
|
+
freeSlots: e.freeSlots,
|
|
552
|
+
bidPerByte: e.bidPerByte,
|
|
553
|
+
addrs,
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
const buf = new Uint8Array(bytes);
|
|
557
|
+
buf[0] = MSG_TRACKER_REPLY;
|
|
558
|
+
buf.set(channelKey, 1);
|
|
559
|
+
writeU32BE(buf, 33, reqId >>> 0);
|
|
560
|
+
buf[37] = Math.max(0, Math.min(255, encoded.length)) & 0xff;
|
|
561
|
+
let offset = 38;
|
|
562
|
+
for (const e of encoded) {
|
|
563
|
+
buf[offset++] = e.hashBytes.length & 0xff;
|
|
564
|
+
buf.set(e.hashBytes, offset);
|
|
565
|
+
offset += e.hashBytes.length;
|
|
566
|
+
writeU16BE(buf, offset, clampU16(e.level));
|
|
567
|
+
offset += 2;
|
|
568
|
+
writeU16BE(buf, offset, clampU16(e.freeSlots));
|
|
569
|
+
offset += 2;
|
|
570
|
+
writeU32BE(buf, offset, Math.max(0, Math.floor(e.bidPerByte)) >>> 0);
|
|
571
|
+
offset += 4;
|
|
572
|
+
buf[offset++] = Math.max(0, Math.min(255, e.addrs.length)) & 0xff;
|
|
573
|
+
for (const a of e.addrs) {
|
|
574
|
+
writeU16BE(buf, offset, a.length);
|
|
575
|
+
offset += 2;
|
|
576
|
+
buf.set(a, offset);
|
|
577
|
+
offset += a.length;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return buf;
|
|
581
|
+
};
|
|
582
|
+
export const encodeTrackerFeedback = (channelKey, candidateHash, event, reason) => {
|
|
583
|
+
const hashBytes = textEncoder.encode(candidateHash);
|
|
584
|
+
const hashLen = Math.max(0, Math.min(255, hashBytes.length));
|
|
585
|
+
const buf = new Uint8Array(1 + 32 + 1 + hashLen + 1 + 1);
|
|
586
|
+
buf[0] = MSG_TRACKER_FEEDBACK;
|
|
587
|
+
buf.set(channelKey, 1);
|
|
588
|
+
buf[33] = hashLen & 0xff;
|
|
589
|
+
buf.set(hashBytes.subarray(0, hashLen), 34);
|
|
590
|
+
buf[34 + hashLen] = event & 0xff;
|
|
591
|
+
buf[34 + hashLen + 1] = reason & 0xff;
|
|
592
|
+
return buf;
|
|
593
|
+
};
|
|
594
|
+
const PARENT_PROBE_REQ_PAYLOAD_BYTES = 4;
|
|
595
|
+
const PARENT_PROBE_REQ_EXTENSION_BYTES = 2 + 1;
|
|
596
|
+
const PARENT_PROBE_REPLY_PAYLOAD_BYTES = 4 + 1 + 2 + 2 + 2 + 2 + 4 + 2 + 4 + 4;
|
|
597
|
+
const PARENT_PROBE_REPLY_RESERVATION_BYTES = 4;
|
|
598
|
+
export const encodeParentProbeReq = (channelKey, reqId, minFreeSlots = 0, reserveRootCapacity = true) => {
|
|
599
|
+
const encodedMinFreeSlots = Math.max(0, Math.floor(minFreeSlots));
|
|
600
|
+
const hasExtension = encodedMinFreeSlots > 0 || !reserveRootCapacity;
|
|
601
|
+
const frame = new FrameWriter(MSG_PARENT_PROBE_REQ, channelKey, PARENT_PROBE_REQ_PAYLOAD_BYTES +
|
|
602
|
+
(hasExtension ? PARENT_PROBE_REQ_EXTENSION_BYTES : 0)).u32(reqId >>> 0);
|
|
603
|
+
if (hasExtension) {
|
|
604
|
+
frame
|
|
605
|
+
.u16(clampU16(encodedMinFreeSlots))
|
|
606
|
+
.u8(reserveRootCapacity ? PARENT_PROBE_REQ_FLAG_RESERVE_ROOT : 0);
|
|
607
|
+
}
|
|
608
|
+
return frame.done();
|
|
609
|
+
};
|
|
610
|
+
export const encodeParentProbeReply = (channelKey, reqId, options) => {
|
|
611
|
+
return new FrameWriter(MSG_PARENT_PROBE_REPLY, channelKey, PARENT_PROBE_REPLY_PAYLOAD_BYTES + PARENT_PROBE_REPLY_RESERVATION_BYTES)
|
|
612
|
+
.u32(reqId >>> 0)
|
|
613
|
+
.u8(options.flags & 0xff)
|
|
614
|
+
.u16(clampU16(options.level))
|
|
615
|
+
.u16(clampU16(options.maxChildren))
|
|
616
|
+
.u16(clampU16(options.freeSlots))
|
|
617
|
+
.u16(clampU16(options.children))
|
|
618
|
+
.u32(Math.max(0, Math.floor(options.haveToExclusive)) >>> 0)
|
|
619
|
+
.u16(clampU16(options.missingSeqs))
|
|
620
|
+
.u32(Math.max(0, Math.floor(options.dataWriteDrops)) >>> 0)
|
|
621
|
+
.u32(Math.max(0, Math.floor(options.droppedForwards)) >>> 0)
|
|
622
|
+
.u32(Math.max(0, Math.floor(options.reservationToken ?? 0)) >>> 0)
|
|
623
|
+
.done();
|
|
624
|
+
};
|
|
625
|
+
export const decodeParentProbeReq = (data) => {
|
|
626
|
+
const frame = FrameReader.control(data, PARENT_PROBE_REQ_PAYLOAD_BYTES);
|
|
627
|
+
if (!frame)
|
|
628
|
+
return undefined;
|
|
629
|
+
const reqId = frame.u32();
|
|
630
|
+
if (reqId == null)
|
|
631
|
+
return undefined;
|
|
632
|
+
let minFreeSlots = 0;
|
|
633
|
+
let probeFlags = PARENT_PROBE_REQ_FLAG_RESERVE_ROOT;
|
|
634
|
+
if (frame.has(2)) {
|
|
635
|
+
minFreeSlots = frame.u16() ?? 0;
|
|
636
|
+
if (frame.has(1)) {
|
|
637
|
+
probeFlags = frame.u8() ?? PARENT_PROBE_REQ_FLAG_RESERVE_ROOT;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
return {
|
|
641
|
+
reqId,
|
|
642
|
+
minFreeSlots,
|
|
643
|
+
reserveRootCapacity: Boolean(probeFlags & PARENT_PROBE_REQ_FLAG_RESERVE_ROOT),
|
|
644
|
+
};
|
|
645
|
+
};
|
|
646
|
+
export const decodeParentProbeReply = (data, hash) => {
|
|
647
|
+
const frame = FrameReader.control(data, PARENT_PROBE_REPLY_PAYLOAD_BYTES);
|
|
648
|
+
if (!frame)
|
|
649
|
+
return undefined;
|
|
650
|
+
const reqId = frame.u32();
|
|
651
|
+
const flags = frame.u8();
|
|
652
|
+
const level = frame.u16();
|
|
653
|
+
const maxChildren = frame.u16();
|
|
654
|
+
const freeSlots = frame.u16();
|
|
655
|
+
const children = frame.u16();
|
|
656
|
+
const haveToExclusive = frame.u32();
|
|
657
|
+
const missingSeqs = frame.u16();
|
|
658
|
+
const dataWriteDrops = frame.u32();
|
|
659
|
+
const droppedForwards = frame.u32();
|
|
660
|
+
if (reqId == null ||
|
|
661
|
+
flags == null ||
|
|
662
|
+
level == null ||
|
|
663
|
+
maxChildren == null ||
|
|
664
|
+
freeSlots == null ||
|
|
665
|
+
children == null ||
|
|
666
|
+
haveToExclusive == null ||
|
|
667
|
+
missingSeqs == null ||
|
|
668
|
+
dataWriteDrops == null ||
|
|
669
|
+
droppedForwards == null) {
|
|
670
|
+
return undefined;
|
|
671
|
+
}
|
|
672
|
+
return {
|
|
673
|
+
reqId,
|
|
674
|
+
hash,
|
|
675
|
+
rooted: Boolean(flags & PARENT_PROBE_FLAG_ROOTED),
|
|
676
|
+
accepting: Boolean(flags & PARENT_PROBE_FLAG_ACCEPTING),
|
|
677
|
+
repairing: Boolean(flags & PARENT_PROBE_FLAG_REPAIRING),
|
|
678
|
+
overloaded: Boolean(flags & PARENT_PROBE_FLAG_OVERLOADED),
|
|
679
|
+
reservationToken: frame.has(PARENT_PROBE_REPLY_RESERVATION_BYTES)
|
|
680
|
+
? (frame.u32() ?? 0)
|
|
681
|
+
: 0,
|
|
682
|
+
level,
|
|
683
|
+
maxChildren,
|
|
684
|
+
freeSlots,
|
|
685
|
+
children,
|
|
686
|
+
haveToExclusive,
|
|
687
|
+
missingSeqs,
|
|
688
|
+
dataWriteDrops,
|
|
689
|
+
droppedForwards,
|
|
690
|
+
};
|
|
691
|
+
};
|
|
692
|
+
export const encodeProviderAnnounce = (namespaceKey, ttlMs, addrs) => {
|
|
693
|
+
const addrCount = Math.max(0, Math.min(255, addrs.length));
|
|
694
|
+
let bytes = 1 + 32 + 4 + 1;
|
|
695
|
+
const addrBytes = new Array(addrCount);
|
|
696
|
+
for (let i = 0; i < addrCount; i++) {
|
|
697
|
+
const b = addrs[i].bytes;
|
|
698
|
+
addrBytes[i] = b;
|
|
699
|
+
bytes += 2 + b.length;
|
|
700
|
+
}
|
|
701
|
+
const buf = new Uint8Array(bytes);
|
|
702
|
+
buf[0] = MSG_PROVIDER_ANNOUNCE;
|
|
703
|
+
buf.set(namespaceKey, 1);
|
|
704
|
+
writeU32BE(buf, 33, Math.max(0, Math.floor(ttlMs)) >>> 0);
|
|
705
|
+
buf[37] = addrCount & 0xff;
|
|
706
|
+
let offset = 38;
|
|
707
|
+
for (let i = 0; i < addrCount; i++) {
|
|
708
|
+
const b = addrBytes[i];
|
|
709
|
+
writeU16BE(buf, offset, b.length);
|
|
710
|
+
offset += 2;
|
|
711
|
+
buf.set(b, offset);
|
|
712
|
+
offset += b.length;
|
|
713
|
+
}
|
|
714
|
+
return buf;
|
|
715
|
+
};
|
|
716
|
+
export const encodeProviderQuery = (namespaceKey, reqId, want, seed) => {
|
|
717
|
+
const buf = new Uint8Array(1 + 32 + 4 + 2 + 4);
|
|
718
|
+
buf[0] = MSG_PROVIDER_QUERY;
|
|
719
|
+
buf.set(namespaceKey, 1);
|
|
720
|
+
writeU32BE(buf, 33, reqId >>> 0);
|
|
721
|
+
writeU16BE(buf, 37, clampU16(want));
|
|
722
|
+
writeU32BE(buf, 39, seed >>> 0);
|
|
723
|
+
return buf;
|
|
724
|
+
};
|
|
725
|
+
const encodeProviderEntries = (entries) => {
|
|
726
|
+
const count = Math.max(0, Math.min(255, entries.length));
|
|
727
|
+
let bytes = 1;
|
|
728
|
+
const encoded = [];
|
|
729
|
+
for (let i = 0; i < count; i++) {
|
|
730
|
+
const e = entries[i];
|
|
731
|
+
const hashBytes = textEncoder.encode(e.hash);
|
|
732
|
+
if (hashBytes.length > 255)
|
|
733
|
+
continue;
|
|
734
|
+
const addrCount = Math.max(0, Math.min(255, e.addrs.length));
|
|
735
|
+
const addrs = e.addrs.slice(0, addrCount);
|
|
736
|
+
bytes += 1 + hashBytes.length + 1;
|
|
737
|
+
for (const a of addrs)
|
|
738
|
+
bytes += 2 + a.length;
|
|
739
|
+
encoded.push({ hashBytes, addrs });
|
|
740
|
+
}
|
|
741
|
+
return { bytes, encoded };
|
|
742
|
+
};
|
|
743
|
+
export const encodeProviderReply = (namespaceKey, reqId, entries) => {
|
|
744
|
+
const { bytes: entryBytes, encoded } = encodeProviderEntries(entries);
|
|
745
|
+
const bytes = 1 + 32 + 4 + entryBytes;
|
|
746
|
+
const buf = new Uint8Array(bytes);
|
|
747
|
+
buf[0] = MSG_PROVIDER_REPLY;
|
|
748
|
+
buf.set(namespaceKey, 1);
|
|
749
|
+
writeU32BE(buf, 33, reqId >>> 0);
|
|
750
|
+
buf[37] = Math.max(0, Math.min(255, encoded.length)) & 0xff;
|
|
751
|
+
let offset = 38;
|
|
752
|
+
for (const e of encoded) {
|
|
753
|
+
buf[offset++] = e.hashBytes.length & 0xff;
|
|
754
|
+
buf.set(e.hashBytes, offset);
|
|
755
|
+
offset += e.hashBytes.length;
|
|
756
|
+
buf[offset++] = Math.max(0, Math.min(255, e.addrs.length)) & 0xff;
|
|
757
|
+
for (const a of e.addrs) {
|
|
758
|
+
writeU16BE(buf, offset, a.length);
|
|
759
|
+
offset += 2;
|
|
760
|
+
buf.set(a, offset);
|
|
761
|
+
offset += a.length;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
return buf;
|
|
765
|
+
};
|
|
766
|
+
export const encodeProviderSubscribe = (namespaceKey, want, ttlMs) => {
|
|
767
|
+
const buf = new Uint8Array(1 + 32 + 2 + 4);
|
|
768
|
+
buf[0] = MSG_PROVIDER_SUBSCRIBE;
|
|
769
|
+
buf.set(namespaceKey, 1);
|
|
770
|
+
writeU16BE(buf, 33, clampU16(want));
|
|
771
|
+
writeU32BE(buf, 35, Math.max(0, Math.floor(ttlMs)) >>> 0);
|
|
772
|
+
return buf;
|
|
773
|
+
};
|
|
774
|
+
export const encodeProviderUnsubscribe = (namespaceKey) => {
|
|
775
|
+
const buf = new Uint8Array(1 + 32);
|
|
776
|
+
buf[0] = MSG_PROVIDER_UNSUBSCRIBE;
|
|
777
|
+
buf.set(namespaceKey, 1);
|
|
778
|
+
return buf;
|
|
779
|
+
};
|
|
780
|
+
export const encodeProviderNotify = (namespaceKey, entries) => {
|
|
781
|
+
const { bytes: entryBytes, encoded } = encodeProviderEntries(entries);
|
|
782
|
+
const bytes = 1 + 32 + entryBytes;
|
|
783
|
+
const buf = new Uint8Array(bytes);
|
|
784
|
+
buf[0] = MSG_PROVIDER_NOTIFY;
|
|
785
|
+
buf.set(namespaceKey, 1);
|
|
786
|
+
buf[33] = Math.max(0, Math.min(255, encoded.length)) & 0xff;
|
|
787
|
+
let offset = 34;
|
|
788
|
+
for (const e of encoded) {
|
|
789
|
+
buf[offset++] = e.hashBytes.length & 0xff;
|
|
790
|
+
buf.set(e.hashBytes, offset);
|
|
791
|
+
offset += e.hashBytes.length;
|
|
792
|
+
buf[offset++] = Math.max(0, Math.min(255, e.addrs.length)) & 0xff;
|
|
793
|
+
for (const a of e.addrs) {
|
|
794
|
+
writeU16BE(buf, offset, a.length);
|
|
795
|
+
offset += 2;
|
|
796
|
+
buf.set(a, offset);
|
|
797
|
+
offset += a.length;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
return buf;
|
|
801
|
+
};
|
|
802
|
+
/** The shared JOIN_ACCEPT/JOIN_REJECT head (reqId) parsed before the
|
|
803
|
+
* pending-join lookup. */
|
|
804
|
+
export const decodeJoinResponseReqId = (data) => {
|
|
805
|
+
if (data.length < 1 + 32 + 4)
|
|
806
|
+
return undefined;
|
|
807
|
+
return readU32BE(data, 33);
|
|
808
|
+
};
|
|
809
|
+
export const decodeJoinAccept = (data) => {
|
|
810
|
+
if (data.length < 1 + 32 + 4 + 2 + 1)
|
|
811
|
+
return undefined;
|
|
812
|
+
const parentLevel = readU16BE(data, 37);
|
|
813
|
+
const routeCount = Math.min(255, data[39]);
|
|
814
|
+
let offset = 40;
|
|
815
|
+
const parentRouteFromRoot = [];
|
|
816
|
+
// Unlike `decodeRoute`, this parser stops consuming at MAX_ROUTE_HOPS,
|
|
817
|
+
// which the have-range appendix offset depends on.
|
|
818
|
+
const max = Math.min(routeCount, MAX_ROUTE_HOPS);
|
|
819
|
+
for (let i = 0; i < max; i++) {
|
|
820
|
+
if (offset + 1 > data.length)
|
|
821
|
+
break;
|
|
822
|
+
const len = data[offset++];
|
|
823
|
+
if (len === 0)
|
|
824
|
+
break;
|
|
825
|
+
if (offset + len > data.length)
|
|
826
|
+
break;
|
|
827
|
+
parentRouteFromRoot.push(textDecoder.decode(data.subarray(offset, offset + len)));
|
|
828
|
+
offset += len;
|
|
829
|
+
}
|
|
830
|
+
const haveRange = offset + 8 <= data.length
|
|
831
|
+
? {
|
|
832
|
+
haveFrom: readU32BE(data, offset),
|
|
833
|
+
haveToExclusive: readU32BE(data, offset + 4),
|
|
834
|
+
}
|
|
835
|
+
: undefined;
|
|
836
|
+
return { parentLevel, parentRouteFromRoot, haveRange };
|
|
837
|
+
};
|
|
838
|
+
export const decodeJoinReject = (data) => {
|
|
839
|
+
if (data.length < 1 + 32 + 4 + 1)
|
|
840
|
+
return undefined;
|
|
841
|
+
const reason = data[37] & 0xff;
|
|
842
|
+
const redirects = [];
|
|
843
|
+
if (data.length >= 1 + 32 + 4 + 1 + 1) {
|
|
844
|
+
const count = Math.min(255, data[38]);
|
|
845
|
+
let offset = 39;
|
|
846
|
+
const max = Math.min(count, JOIN_REJECT_REDIRECT_MAX);
|
|
847
|
+
for (let i = 0; i < max; i++) {
|
|
848
|
+
if (offset + 1 > data.length)
|
|
849
|
+
break;
|
|
850
|
+
const hashLen = data[offset++];
|
|
851
|
+
if (hashLen === 0)
|
|
852
|
+
break;
|
|
853
|
+
if (offset + hashLen > data.length)
|
|
854
|
+
break;
|
|
855
|
+
const hash = textDecoder.decode(data.subarray(offset, offset + hashLen));
|
|
856
|
+
offset += hashLen;
|
|
857
|
+
if (offset + 1 > data.length)
|
|
858
|
+
break;
|
|
859
|
+
const addrCount = Math.min(255, data[offset++]);
|
|
860
|
+
const addrs = [];
|
|
861
|
+
const addrMax = Math.min(addrCount, JOIN_REJECT_REDIRECT_ADDR_MAX);
|
|
862
|
+
for (let j = 0; j < addrMax; j++) {
|
|
863
|
+
if (offset + 2 > data.length)
|
|
864
|
+
break;
|
|
865
|
+
const len = readU16BE(data, offset);
|
|
866
|
+
offset += 2;
|
|
867
|
+
if (offset + len > data.length)
|
|
868
|
+
break;
|
|
869
|
+
addrs.push(data.subarray(offset, offset + len));
|
|
870
|
+
offset += len;
|
|
871
|
+
}
|
|
872
|
+
redirects.push({ hash, addrs });
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
return { reason, redirects };
|
|
876
|
+
};
|
|
877
|
+
export const decodeEnd = (data) => {
|
|
878
|
+
if (data.length < 1 + 32 + 4)
|
|
879
|
+
return undefined;
|
|
880
|
+
return readU32BE(data, 33);
|
|
881
|
+
};
|
|
882
|
+
/** MSG_REPAIR_REQ / MSG_FETCH_REQ sequence list: `count` capped by the
|
|
883
|
+
* bytes actually present. */
|
|
884
|
+
export const decodeRepairSeqs = (data) => {
|
|
885
|
+
if (data.length < 1 + 32 + 4 + 1)
|
|
886
|
+
return undefined;
|
|
887
|
+
const count = data[37];
|
|
888
|
+
const max = Math.min(count, Math.floor((data.length - 38) / 4));
|
|
889
|
+
const seqs = [];
|
|
890
|
+
for (let i = 0; i < max; i++) {
|
|
891
|
+
seqs.push(readU32BE(data, 38 + i * 4));
|
|
892
|
+
}
|
|
893
|
+
return seqs;
|
|
894
|
+
};
|
|
895
|
+
export const decodeIHave = (data) => {
|
|
896
|
+
if (data.length < 1 + 32 + 4 + 4)
|
|
897
|
+
return undefined;
|
|
898
|
+
return {
|
|
899
|
+
haveFrom: readU32BE(data, 33),
|
|
900
|
+
haveToExclusive: readU32BE(data, 37),
|
|
901
|
+
};
|
|
902
|
+
};
|
|
903
|
+
export const decodeUnicast = (data) => {
|
|
904
|
+
if (data.length < 1 + 32 + 1 + 1)
|
|
905
|
+
return undefined;
|
|
906
|
+
const flags = data[33] & 0xff;
|
|
907
|
+
let offset = 34;
|
|
908
|
+
let ackToken;
|
|
909
|
+
if (flags & UNICAST_FLAG_ACK) {
|
|
910
|
+
if (data.length < offset + 8 + 1)
|
|
911
|
+
return undefined;
|
|
912
|
+
ackToken = readU64BE(data, offset);
|
|
913
|
+
offset += 8;
|
|
914
|
+
}
|
|
915
|
+
const routeCount = Math.min(255, data[offset]);
|
|
916
|
+
offset += 1;
|
|
917
|
+
const decoded = decodeRoute(data, offset, routeCount);
|
|
918
|
+
const route = decoded.route;
|
|
919
|
+
offset = decoded.offset;
|
|
920
|
+
let replyRoute;
|
|
921
|
+
if (ackToken != null) {
|
|
922
|
+
if (data.length < offset + 1)
|
|
923
|
+
return undefined;
|
|
924
|
+
const replyCount = Math.min(255, data[offset]);
|
|
925
|
+
offset += 1;
|
|
926
|
+
const decodedReply = decodeRoute(data, offset, replyCount);
|
|
927
|
+
replyRoute = decodedReply.route;
|
|
928
|
+
offset = decodedReply.offset;
|
|
929
|
+
}
|
|
930
|
+
return {
|
|
931
|
+
ackToken,
|
|
932
|
+
route,
|
|
933
|
+
replyRoute,
|
|
934
|
+
payloadOffset: Math.min(offset, data.length),
|
|
935
|
+
};
|
|
936
|
+
};
|
|
937
|
+
export const decodeUnicastAck = (data) => {
|
|
938
|
+
if (data.length < 1 + 32 + 8 + 1)
|
|
939
|
+
return undefined;
|
|
940
|
+
const ackToken = readU64BE(data, 33);
|
|
941
|
+
const routeCount = Math.min(255, data[41]);
|
|
942
|
+
return { ackToken, route: decodeRoute(data, 42, routeCount).route };
|
|
943
|
+
};
|
|
944
|
+
export const decodeRouteQuery = (data) => {
|
|
945
|
+
if (data.length < 1 + 32 + 4 + 1)
|
|
946
|
+
return undefined;
|
|
947
|
+
const reqId = readU32BE(data, 33);
|
|
948
|
+
const hashLen = data[37];
|
|
949
|
+
// A zero/overflowing target is answered with an empty reply, not dropped.
|
|
950
|
+
const targetHash = hashLen === 0 || 38 + hashLen > data.length
|
|
951
|
+
? undefined
|
|
952
|
+
: textDecoder.decode(data.subarray(38, 38 + hashLen));
|
|
953
|
+
return { reqId, targetHash };
|
|
954
|
+
};
|
|
955
|
+
export const decodeRouteReply = (data) => {
|
|
956
|
+
if (data.length < 1 + 32 + 4 + 1)
|
|
957
|
+
return undefined;
|
|
958
|
+
const reqId = readU32BE(data, 33);
|
|
959
|
+
const routeCount = Math.min(255, data[37]);
|
|
960
|
+
return { reqId, route: decodeRoute(data, 38, routeCount).route };
|
|
961
|
+
};
|
|
962
|
+
const decodeAddrList = (data, offsetStart, addrCount) => {
|
|
963
|
+
let offset = offsetStart;
|
|
964
|
+
const addrs = [];
|
|
965
|
+
const max = Math.min(addrCount, 16);
|
|
966
|
+
for (let i = 0; i < max; i++) {
|
|
967
|
+
if (offset + 2 > data.length)
|
|
968
|
+
break;
|
|
969
|
+
const len = readU16BE(data, offset);
|
|
970
|
+
offset += 2;
|
|
971
|
+
if (offset + len > data.length)
|
|
972
|
+
break;
|
|
973
|
+
addrs.push(data.subarray(offset, offset + len));
|
|
974
|
+
offset += len;
|
|
975
|
+
}
|
|
976
|
+
return addrs;
|
|
977
|
+
};
|
|
978
|
+
export const decodeTrackerAnnounce = (data) => {
|
|
979
|
+
if (data.length < 1 + 32 + 4 + 2 + 2 + 2 + 4 + 1)
|
|
980
|
+
return undefined;
|
|
981
|
+
return {
|
|
982
|
+
ttlMs: readU32BE(data, 33),
|
|
983
|
+
level: readU16BE(data, 37),
|
|
984
|
+
// maxChildren at offset 39 is kept in the wire format but unused.
|
|
985
|
+
freeSlots: readU16BE(data, 41),
|
|
986
|
+
bidPerByte: readU32BE(data, 43),
|
|
987
|
+
addrs: decodeAddrList(data, 48, data[47]),
|
|
988
|
+
};
|
|
989
|
+
};
|
|
990
|
+
export const decodeTrackerQuery = (data) => {
|
|
991
|
+
if (data.length < 1 + 32 + 4 + 2)
|
|
992
|
+
return undefined;
|
|
993
|
+
return { reqId: readU32BE(data, 33), want: readU16BE(data, 37) };
|
|
994
|
+
};
|
|
995
|
+
export const decodeTrackerReply = (data) => {
|
|
996
|
+
if (data.length < 1 + 32 + 4 + 1)
|
|
997
|
+
return undefined;
|
|
998
|
+
const reqId = readU32BE(data, 33);
|
|
999
|
+
const count = data[37];
|
|
1000
|
+
let offset = 38;
|
|
1001
|
+
const entries = [];
|
|
1002
|
+
const max = Math.min(count, 255);
|
|
1003
|
+
for (let i = 0; i < max; i++) {
|
|
1004
|
+
if (offset + 1 > data.length)
|
|
1005
|
+
break;
|
|
1006
|
+
const hashLen = data[offset++];
|
|
1007
|
+
if (offset + hashLen > data.length)
|
|
1008
|
+
break;
|
|
1009
|
+
const hash = textDecoder.decode(data.subarray(offset, offset + hashLen));
|
|
1010
|
+
offset += hashLen;
|
|
1011
|
+
if (offset + 2 + 2 + 4 + 1 > data.length)
|
|
1012
|
+
break;
|
|
1013
|
+
const level = readU16BE(data, offset);
|
|
1014
|
+
offset += 2;
|
|
1015
|
+
const freeSlots = readU16BE(data, offset);
|
|
1016
|
+
offset += 2;
|
|
1017
|
+
const bidPerByte = readU32BE(data, offset);
|
|
1018
|
+
offset += 4;
|
|
1019
|
+
const addrCount = data[offset++];
|
|
1020
|
+
const addrs = [];
|
|
1021
|
+
const addrMax = Math.min(addrCount, 16);
|
|
1022
|
+
for (let j = 0; j < addrMax; j++) {
|
|
1023
|
+
if (offset + 2 > data.length)
|
|
1024
|
+
break;
|
|
1025
|
+
const len = readU16BE(data, offset);
|
|
1026
|
+
offset += 2;
|
|
1027
|
+
if (offset + len > data.length)
|
|
1028
|
+
break;
|
|
1029
|
+
addrs.push(data.subarray(offset, offset + len));
|
|
1030
|
+
offset += len;
|
|
1031
|
+
}
|
|
1032
|
+
entries.push({ hash, level, freeSlots, bidPerByte, addrs });
|
|
1033
|
+
}
|
|
1034
|
+
return { reqId, entries };
|
|
1035
|
+
};
|
|
1036
|
+
export const decodeTrackerFeedback = (data) => {
|
|
1037
|
+
if (data.length < 1 + 32 + 1 + 1 + 1)
|
|
1038
|
+
return undefined;
|
|
1039
|
+
const hashLen = data[33];
|
|
1040
|
+
const offset = 34;
|
|
1041
|
+
if (offset + hashLen + 2 > data.length)
|
|
1042
|
+
return undefined;
|
|
1043
|
+
return {
|
|
1044
|
+
candidateHash: textDecoder.decode(data.subarray(offset, offset + hashLen)),
|
|
1045
|
+
event: data[offset + hashLen] & 0xff,
|
|
1046
|
+
reason: data[offset + hashLen + 1] & 0xff,
|
|
1047
|
+
};
|
|
1048
|
+
};
|
|
1049
|
+
export const decodeProviderAnnounce = (data) => {
|
|
1050
|
+
if (data.length < 1 + 32 + 4 + 1)
|
|
1051
|
+
return undefined;
|
|
1052
|
+
return {
|
|
1053
|
+
ttlMs: readU32BE(data, 33),
|
|
1054
|
+
addrs: decodeAddrList(data, 38, data[37]),
|
|
1055
|
+
};
|
|
1056
|
+
};
|
|
1057
|
+
export const decodeProviderQuery = (data) => {
|
|
1058
|
+
if (data.length < 1 + 32 + 4 + 2 + 4)
|
|
1059
|
+
return undefined;
|
|
1060
|
+
return {
|
|
1061
|
+
reqId: readU32BE(data, 33),
|
|
1062
|
+
want: readU16BE(data, 37),
|
|
1063
|
+
seed: readU32BE(data, 39),
|
|
1064
|
+
};
|
|
1065
|
+
};
|
|
1066
|
+
/** `decodeProviderEntries` with the multiaddr construction left to the
|
|
1067
|
+
* caller: entries with an empty hash are consumed but skipped. */
|
|
1068
|
+
const decodeProviderEntriesRaw = (data, offsetStart, maxCount) => {
|
|
1069
|
+
let offset = offsetStart;
|
|
1070
|
+
const providers = [];
|
|
1071
|
+
const limit = Math.min(maxCount, 255);
|
|
1072
|
+
for (let i = 0; i < limit; i++) {
|
|
1073
|
+
if (offset + 1 > data.length)
|
|
1074
|
+
break;
|
|
1075
|
+
const hashLen = data[offset++];
|
|
1076
|
+
if (offset + hashLen > data.length)
|
|
1077
|
+
break;
|
|
1078
|
+
const hash = textDecoder.decode(data.subarray(offset, offset + hashLen));
|
|
1079
|
+
offset += hashLen;
|
|
1080
|
+
if (offset + 1 > data.length)
|
|
1081
|
+
break;
|
|
1082
|
+
const addrCount = data[offset++];
|
|
1083
|
+
const addrs = [];
|
|
1084
|
+
const addrMax = Math.min(addrCount, 16);
|
|
1085
|
+
for (let j = 0; j < addrMax; j++) {
|
|
1086
|
+
if (offset + 2 > data.length)
|
|
1087
|
+
break;
|
|
1088
|
+
const len = readU16BE(data, offset);
|
|
1089
|
+
offset += 2;
|
|
1090
|
+
if (offset + len > data.length)
|
|
1091
|
+
break;
|
|
1092
|
+
addrs.push(data.subarray(offset, offset + len));
|
|
1093
|
+
offset += len;
|
|
1094
|
+
}
|
|
1095
|
+
if (!hash)
|
|
1096
|
+
continue;
|
|
1097
|
+
providers.push({ hash, addrs });
|
|
1098
|
+
}
|
|
1099
|
+
return providers;
|
|
1100
|
+
};
|
|
1101
|
+
export const decodeProviderReply = (data) => {
|
|
1102
|
+
if (data.length < 1 + 32 + 4 + 1)
|
|
1103
|
+
return undefined;
|
|
1104
|
+
return {
|
|
1105
|
+
reqId: readU32BE(data, 33),
|
|
1106
|
+
entries: decodeProviderEntriesRaw(data, 38, data[37]),
|
|
1107
|
+
};
|
|
1108
|
+
};
|
|
1109
|
+
export const decodeProviderNotify = (data) => {
|
|
1110
|
+
if (data.length < 1 + 32 + 1)
|
|
1111
|
+
return undefined;
|
|
1112
|
+
return { entries: decodeProviderEntriesRaw(data, 34, data[33]) };
|
|
1113
|
+
};
|
|
1114
|
+
export const decodeProviderSubscribe = (data) => {
|
|
1115
|
+
if (data.length < 1 + 32 + 2 + 4)
|
|
1116
|
+
return undefined;
|
|
1117
|
+
return { want: readU16BE(data, 33), ttlMs: readU32BE(data, 35) };
|
|
1118
|
+
};
|
|
1119
|
+
export const decodeProviderEntries = (data, offsetStart, maxCount) => {
|
|
1120
|
+
let offset = offsetStart;
|
|
1121
|
+
const providers = [];
|
|
1122
|
+
const limit = Math.min(maxCount, 255);
|
|
1123
|
+
for (let i = 0; i < limit; i++) {
|
|
1124
|
+
if (offset + 1 > data.length)
|
|
1125
|
+
break;
|
|
1126
|
+
const hashLen = data[offset++];
|
|
1127
|
+
if (offset + hashLen > data.length)
|
|
1128
|
+
break;
|
|
1129
|
+
const hash = textDecoder.decode(data.subarray(offset, offset + hashLen));
|
|
1130
|
+
offset += hashLen;
|
|
1131
|
+
if (offset + 1 > data.length)
|
|
1132
|
+
break;
|
|
1133
|
+
const addrCount = data[offset++];
|
|
1134
|
+
const addrs = [];
|
|
1135
|
+
const addrMax = Math.min(addrCount, 16);
|
|
1136
|
+
for (let j = 0; j < addrMax; j++) {
|
|
1137
|
+
if (offset + 2 > data.length)
|
|
1138
|
+
break;
|
|
1139
|
+
const len = readU16BE(data, offset);
|
|
1140
|
+
offset += 2;
|
|
1141
|
+
if (offset + len > data.length)
|
|
1142
|
+
break;
|
|
1143
|
+
const bytes = data.subarray(offset, offset + len);
|
|
1144
|
+
offset += len;
|
|
1145
|
+
try {
|
|
1146
|
+
addrs.push(multiaddr(bytes));
|
|
1147
|
+
}
|
|
1148
|
+
catch {
|
|
1149
|
+
// ignore invalid
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
if (!hash)
|
|
1153
|
+
continue;
|
|
1154
|
+
providers.push({ hash, addrs });
|
|
1155
|
+
}
|
|
1156
|
+
return { providers, offset };
|
|
1157
|
+
};
|
|
1158
|
+
export const tsFanoutWireCodec = {
|
|
1159
|
+
encodeJoinReq,
|
|
1160
|
+
encodeJoinAccept,
|
|
1161
|
+
encodeJoinReject,
|
|
1162
|
+
encodeKick,
|
|
1163
|
+
encodeEnd,
|
|
1164
|
+
encodeRepairReq,
|
|
1165
|
+
encodeFetchReq,
|
|
1166
|
+
encodeIHave,
|
|
1167
|
+
encodeData,
|
|
1168
|
+
encodePublishProxy,
|
|
1169
|
+
encodeLeave,
|
|
1170
|
+
encodeUnicast,
|
|
1171
|
+
encodeUnicastAck,
|
|
1172
|
+
encodeRouteQuery,
|
|
1173
|
+
encodeRouteReply,
|
|
1174
|
+
encodeTrackerAnnounce,
|
|
1175
|
+
encodeTrackerQuery,
|
|
1176
|
+
encodeTrackerReply,
|
|
1177
|
+
encodeTrackerFeedback,
|
|
1178
|
+
encodeParentProbeReq,
|
|
1179
|
+
encodeParentProbeReply,
|
|
1180
|
+
encodeProviderAnnounce,
|
|
1181
|
+
encodeProviderQuery,
|
|
1182
|
+
encodeProviderReply,
|
|
1183
|
+
encodeProviderSubscribe,
|
|
1184
|
+
encodeProviderUnsubscribe,
|
|
1185
|
+
encodeProviderNotify,
|
|
1186
|
+
decodeJoinReq,
|
|
1187
|
+
decodeJoinResponseReqId,
|
|
1188
|
+
decodeJoinAccept,
|
|
1189
|
+
decodeJoinReject,
|
|
1190
|
+
decodeEnd,
|
|
1191
|
+
decodeRepairSeqs,
|
|
1192
|
+
decodeIHave,
|
|
1193
|
+
decodeUnicast,
|
|
1194
|
+
decodeUnicastAck,
|
|
1195
|
+
decodeRouteQuery,
|
|
1196
|
+
decodeRouteReply,
|
|
1197
|
+
decodeTrackerAnnounce,
|
|
1198
|
+
decodeTrackerQuery,
|
|
1199
|
+
decodeTrackerReply,
|
|
1200
|
+
decodeTrackerFeedback,
|
|
1201
|
+
decodeParentProbeReq,
|
|
1202
|
+
decodeParentProbeReply,
|
|
1203
|
+
decodeProviderAnnounce,
|
|
1204
|
+
decodeProviderQuery,
|
|
1205
|
+
decodeProviderReply,
|
|
1206
|
+
decodeProviderNotify,
|
|
1207
|
+
decodeProviderSubscribe,
|
|
1208
|
+
};
|
|
1209
|
+
//# sourceMappingURL=fanout-tree-codec.js.map
|