@hashtree/core 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +2 -1
- package/dist/builder.js.map +1 -1
- package/dist/compare.d.ts +2 -0
- package/dist/compare.d.ts.map +1 -0
- package/dist/compare.js +8 -0
- package/dist/compare.js.map +1 -0
- package/dist/encrypted.d.ts.map +1 -1
- package/dist/encrypted.js +28 -18
- package/dist/encrypted.js.map +1 -1
- package/dist/hashtree.js +1 -1
- package/dist/hashtree.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/store/blossom.d.ts.map +1 -1
- package/dist/store/blossom.js +52 -22
- package/dist/store/blossom.js.map +1 -1
- package/dist/store/fallback.d.ts +3 -1
- package/dist/store/fallback.d.ts.map +1 -1
- package/dist/store/fallback.js +60 -24
- package/dist/store/fallback.js.map +1 -1
- package/dist/tree/create.d.ts.map +1 -1
- package/dist/tree/create.js +2 -1
- package/dist/tree/create.js.map +1 -1
- package/dist/types.d.ts +14 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -3
- package/dist/resolver/index.d.ts +0 -5
- package/dist/resolver/index.d.ts.map +0 -1
- package/dist/resolver/index.js +0 -5
- package/dist/resolver/index.js.map +0 -1
- package/dist/resolver/nostr.d.ts +0 -82
- package/dist/resolver/nostr.d.ts.map +0 -1
- package/dist/resolver/nostr.js +0 -868
- package/dist/resolver/nostr.js.map +0 -1
- package/dist/store/dexie.d.ts +0 -44
- package/dist/store/dexie.d.ts.map +0 -1
- package/dist/store/dexie.js +0 -196
- package/dist/store/dexie.js.map +0 -1
- package/dist/store/opfs.d.ts +0 -56
- package/dist/store/opfs.d.ts.map +0 -1
- package/dist/store/opfs.js +0 -200
- package/dist/store/opfs.js.map +0 -1
- package/dist/webrtc/index.d.ts +0 -4
- package/dist/webrtc/index.d.ts.map +0 -1
- package/dist/webrtc/index.js +0 -4
- package/dist/webrtc/index.js.map +0 -1
- package/dist/webrtc/lruCache.d.ts +0 -20
- package/dist/webrtc/lruCache.d.ts.map +0 -1
- package/dist/webrtc/lruCache.js +0 -59
- package/dist/webrtc/lruCache.js.map +0 -1
- package/dist/webrtc/peer.d.ts +0 -122
- package/dist/webrtc/peer.d.ts.map +0 -1
- package/dist/webrtc/peer.js +0 -583
- package/dist/webrtc/peer.js.map +0 -1
- package/dist/webrtc/protocol.d.ts +0 -76
- package/dist/webrtc/protocol.d.ts.map +0 -1
- package/dist/webrtc/protocol.js +0 -167
- package/dist/webrtc/protocol.js.map +0 -1
- package/dist/webrtc/store.d.ts +0 -190
- package/dist/webrtc/store.d.ts.map +0 -1
- package/dist/webrtc/store.js +0 -1043
- package/dist/webrtc/store.js.map +0 -1
- package/dist/webrtc/types.d.ts +0 -196
- package/dist/webrtc/types.d.ts.map +0 -1
- package/dist/webrtc/types.js +0 -46
- package/dist/webrtc/types.js.map +0 -1
package/dist/webrtc/peer.js
DELETED
|
@@ -1,583 +0,0 @@
|
|
|
1
|
-
import { MAX_HTL, MSG_TYPE_REQUEST, MSG_TYPE_RESPONSE, FRAGMENT_SIZE, FRAGMENT_STALL_TIMEOUT, FRAGMENT_TOTAL_TIMEOUT, MAX_PENDING_REASSEMBLIES, } from './types.js';
|
|
2
|
-
import { LRUCache } from './lruCache.js';
|
|
3
|
-
import { encodeRequest, encodeResponse, parseMessage, createRequest, createResponse, createFragmentResponse, isFragmented, clearPendingRequests, generatePeerHTLConfig, decrementHTL, shouldForward, hashToKey, verifyHash, } from './protocol.js';
|
|
4
|
-
const ICE_SERVERS = [
|
|
5
|
-
{ urls: 'stun:stun.iris.to:3478' },
|
|
6
|
-
{ urls: 'stun:stun.l.google.com:19302' },
|
|
7
|
-
{ urls: 'stun:stun.cloudflare.com:3478' },
|
|
8
|
-
];
|
|
9
|
-
// Batch ICE candidates to reduce signaling messages
|
|
10
|
-
const ICE_BATCH_DELAY = 100; // ms to wait before sending batched candidates
|
|
11
|
-
// Default LRU cache size
|
|
12
|
-
const THEIR_REQUESTS_SIZE = 200;
|
|
13
|
-
export class Peer {
|
|
14
|
-
peerId;
|
|
15
|
-
pubkey;
|
|
16
|
-
direction;
|
|
17
|
-
pc;
|
|
18
|
-
dataChannel = null;
|
|
19
|
-
localStore;
|
|
20
|
-
sendSignaling;
|
|
21
|
-
onClose;
|
|
22
|
-
onConnected;
|
|
23
|
-
onConnectedFired = false; // Guard against double-firing
|
|
24
|
-
debug;
|
|
25
|
-
// Perfect negotiation state
|
|
26
|
-
makingOffer = false;
|
|
27
|
-
ignoreOffer = false;
|
|
28
|
-
isPolite; // true if we should rollback on collision
|
|
29
|
-
myPeerId; // our peer ID for comparison
|
|
30
|
-
// Requests we sent TO this peer (keyed by hash hex)
|
|
31
|
-
ourRequests = new Map();
|
|
32
|
-
// Requests this peer sent TO US that we couldn't fulfill (keyed by hash hex)
|
|
33
|
-
// We track these so we can push data back if we get it later
|
|
34
|
-
theirRequests = new LRUCache(THEIR_REQUESTS_SIZE);
|
|
35
|
-
requestTimeout;
|
|
36
|
-
pendingCandidates = [];
|
|
37
|
-
candidateBatchTimeout = null;
|
|
38
|
-
queuedRemoteCandidates = [];
|
|
39
|
-
// Callback to forward request to other peers when we don't have data locally
|
|
40
|
-
// htl parameter is the decremented HTL to use when forwarding
|
|
41
|
-
onForwardRequest;
|
|
42
|
-
// Per-peer stats tracking
|
|
43
|
-
stats = {
|
|
44
|
-
requestsSent: 0,
|
|
45
|
-
requestsReceived: 0,
|
|
46
|
-
responsesSent: 0,
|
|
47
|
-
responsesReceived: 0,
|
|
48
|
-
receiveErrors: 0,
|
|
49
|
-
fragmentsSent: 0,
|
|
50
|
-
fragmentsReceived: 0,
|
|
51
|
-
fragmentTimeouts: 0,
|
|
52
|
-
reassembliesCompleted: 0,
|
|
53
|
-
bytesSent: 0,
|
|
54
|
-
bytesReceived: 0,
|
|
55
|
-
bytesForwarded: 0,
|
|
56
|
-
};
|
|
57
|
-
// Fragment reassembly tracking
|
|
58
|
-
pendingReassemblies = new Map();
|
|
59
|
-
reassemblyCleanupInterval;
|
|
60
|
-
// Per-peer HTL decrement config (Freenet-style probabilistic)
|
|
61
|
-
htlConfig;
|
|
62
|
-
createdAt;
|
|
63
|
-
connectedAt;
|
|
64
|
-
constructor(options) {
|
|
65
|
-
this.peerId = options.peerId.toString();
|
|
66
|
-
this.pubkey = options.peerId.pubkey;
|
|
67
|
-
this.direction = options.direction;
|
|
68
|
-
this.localStore = options.localStore;
|
|
69
|
-
this.sendSignaling = options.sendSignaling;
|
|
70
|
-
this.onClose = options.onClose;
|
|
71
|
-
this.onConnected = options.onConnected;
|
|
72
|
-
this.onForwardRequest = options.onForwardRequest;
|
|
73
|
-
this.requestTimeout = options.requestTimeout ?? 500;
|
|
74
|
-
this.debug = options.debug ?? false;
|
|
75
|
-
this.createdAt = Date.now();
|
|
76
|
-
// Generate random HTL config for this peer (Freenet-style)
|
|
77
|
-
this.htlConfig = generatePeerHTLConfig();
|
|
78
|
-
// Perfect negotiation: polite peer (smaller ID) rolls back on collision
|
|
79
|
-
this.myPeerId = options.myPeerId;
|
|
80
|
-
this.isPolite = options.myPeerId < options.peerId.uuid;
|
|
81
|
-
// Start fragment reassembly cleanup interval
|
|
82
|
-
this.reassemblyCleanupInterval = setInterval(() => this.cleanupStaleReassemblies(), 5000);
|
|
83
|
-
this.pc = new RTCPeerConnection({ iceServers: ICE_SERVERS });
|
|
84
|
-
this.setupPeerConnection();
|
|
85
|
-
}
|
|
86
|
-
log(...args) {
|
|
87
|
-
if (this.debug) {
|
|
88
|
-
console.log(`[Peer ${this.peerId.slice(0, 12)}]`, ...args);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
get state() {
|
|
92
|
-
return this.pc.connectionState;
|
|
93
|
-
}
|
|
94
|
-
get isConnected() {
|
|
95
|
-
return this.pc.connectionState === 'connected' &&
|
|
96
|
-
this.dataChannel?.readyState === 'open';
|
|
97
|
-
}
|
|
98
|
-
get pendingTheirRequestsCount() {
|
|
99
|
-
return this.theirRequests.size;
|
|
100
|
-
}
|
|
101
|
-
scheduleCandidateBatch() {
|
|
102
|
-
if (this.candidateBatchTimeout)
|
|
103
|
-
return;
|
|
104
|
-
this.candidateBatchTimeout = setTimeout(() => {
|
|
105
|
-
this.candidateBatchTimeout = null;
|
|
106
|
-
if (this.pendingCandidates.length > 0) {
|
|
107
|
-
const candidates = this.pendingCandidates;
|
|
108
|
-
this.pendingCandidates = [];
|
|
109
|
-
// Send as batch (convert RTCIceCandidateInit to IceCandidate format)
|
|
110
|
-
this.sendSignaling({
|
|
111
|
-
type: 'candidates',
|
|
112
|
-
candidates: candidates.map((c) => ({
|
|
113
|
-
candidate: c.candidate,
|
|
114
|
-
sdpMLineIndex: c.sdpMLineIndex ?? undefined,
|
|
115
|
-
sdpMid: c.sdpMid ?? undefined,
|
|
116
|
-
})),
|
|
117
|
-
targetPeerId: this.peerId,
|
|
118
|
-
peerId: '', // Will be set by caller
|
|
119
|
-
}).catch((err) => {
|
|
120
|
-
this.log('Failed to send candidates batch:', err);
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
}, ICE_BATCH_DELAY);
|
|
124
|
-
}
|
|
125
|
-
setupPeerConnection() {
|
|
126
|
-
this.pc.onicecandidate = (event) => {
|
|
127
|
-
if (event.candidate) {
|
|
128
|
-
this.pendingCandidates.push(event.candidate.toJSON());
|
|
129
|
-
this.scheduleCandidateBatch();
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
this.pc.onconnectionstatechange = () => {
|
|
133
|
-
if (this.pc.connectionState === 'connected') {
|
|
134
|
-
this.connectedAt = Date.now();
|
|
135
|
-
// Only trigger onConnected if data channel is also ready
|
|
136
|
-
// (it may already be open, or will fire via channel.onopen)
|
|
137
|
-
if (this.dataChannel?.readyState === 'open' && !this.onConnectedFired) {
|
|
138
|
-
this.onConnectedFired = true;
|
|
139
|
-
this.onConnected?.();
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
else if (this.pc.connectionState === 'failed' ||
|
|
143
|
-
this.pc.connectionState === 'closed' ||
|
|
144
|
-
this.pc.connectionState === 'disconnected') {
|
|
145
|
-
this.close();
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
this.pc.ondatachannel = (event) => {
|
|
149
|
-
this.dataChannel = event.channel;
|
|
150
|
-
this.setupDataChannel(this.dataChannel);
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
setupDataChannel(channel) {
|
|
154
|
-
channel.binaryType = 'arraybuffer';
|
|
155
|
-
channel.onopen = () => {
|
|
156
|
-
// If PC is already connected, fire onConnected now
|
|
157
|
-
// (handles case where data channel opens after PC connects)
|
|
158
|
-
if (this.pc.connectionState === 'connected' && !this.onConnectedFired) {
|
|
159
|
-
this.onConnectedFired = true;
|
|
160
|
-
this.onConnected?.();
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
channel.onclose = () => {
|
|
164
|
-
this.log('Data channel closed');
|
|
165
|
-
this.close();
|
|
166
|
-
};
|
|
167
|
-
channel.onmessage = async (event) => {
|
|
168
|
-
// All messages are binary with type prefix
|
|
169
|
-
if (event.data instanceof ArrayBuffer) {
|
|
170
|
-
await this.handleMessage(event.data);
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
async handleMessage(data) {
|
|
175
|
-
try {
|
|
176
|
-
const msg = parseMessage(data);
|
|
177
|
-
if (!msg) {
|
|
178
|
-
this.log('Failed to parse message');
|
|
179
|
-
this.stats.receiveErrors++;
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
if (msg.type === MSG_TYPE_REQUEST) {
|
|
183
|
-
await this.handleRequest(msg.body);
|
|
184
|
-
}
|
|
185
|
-
else if (msg.type === MSG_TYPE_RESPONSE) {
|
|
186
|
-
const res = msg.body;
|
|
187
|
-
// Handle fragmented vs unfragmented responses
|
|
188
|
-
let finalData;
|
|
189
|
-
let hash;
|
|
190
|
-
if (isFragmented(res)) {
|
|
191
|
-
// Fragmented response - reassemble
|
|
192
|
-
const assembled = this.handleFragmentResponse(res);
|
|
193
|
-
if (!assembled) {
|
|
194
|
-
return; // Incomplete, wait for more fragments
|
|
195
|
-
}
|
|
196
|
-
finalData = assembled;
|
|
197
|
-
hash = res.h;
|
|
198
|
-
}
|
|
199
|
-
else {
|
|
200
|
-
// Unfragmented response - use directly
|
|
201
|
-
finalData = res.d;
|
|
202
|
-
hash = res.h;
|
|
203
|
-
}
|
|
204
|
-
// Now handle the complete response (verify hash and resolve pending request)
|
|
205
|
-
const hashKey = hashToKey(hash);
|
|
206
|
-
const pending = this.ourRequests.get(hashKey);
|
|
207
|
-
if (!pending) {
|
|
208
|
-
return; // No pending request for this hash
|
|
209
|
-
}
|
|
210
|
-
clearTimeout(pending.timeout);
|
|
211
|
-
this.ourRequests.delete(hashKey);
|
|
212
|
-
const isValid = await verifyHash(finalData, hash);
|
|
213
|
-
if (isValid) {
|
|
214
|
-
pending.resolve(finalData);
|
|
215
|
-
this.stats.responsesReceived++;
|
|
216
|
-
this.stats.bytesReceived += finalData.length;
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
pending.resolve(null);
|
|
220
|
-
this.stats.receiveErrors++;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
catch (err) {
|
|
225
|
-
this.log('Error handling message:', err);
|
|
226
|
-
this.stats.receiveErrors++;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
async handleRequest(req) {
|
|
230
|
-
const htl = req.htl ?? MAX_HTL;
|
|
231
|
-
const hash = req.h;
|
|
232
|
-
const hashKey = hashToKey(hash);
|
|
233
|
-
this.stats.requestsReceived++;
|
|
234
|
-
// Try local store first
|
|
235
|
-
if (this.localStore) {
|
|
236
|
-
const data = await this.localStore.get(hash);
|
|
237
|
-
if (data) {
|
|
238
|
-
this.sendResponse(hash, data);
|
|
239
|
-
this.stats.responsesSent++;
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
// Not found locally - check if we should forward based on HTL
|
|
244
|
-
if (this.onForwardRequest && shouldForward(htl)) {
|
|
245
|
-
// Track this request so we can push data back later if we get it
|
|
246
|
-
this.theirRequests.set(hashKey, {
|
|
247
|
-
hash,
|
|
248
|
-
requestedAt: Date.now(),
|
|
249
|
-
});
|
|
250
|
-
// Decrement HTL before forwarding (Freenet-style per-peer decrement)
|
|
251
|
-
const forwardHTL = decrementHTL(htl, this.htlConfig);
|
|
252
|
-
// Forward to other peers (excluding this one)
|
|
253
|
-
const data = await this.onForwardRequest(hash, this.peerId, forwardHTL);
|
|
254
|
-
if (data) {
|
|
255
|
-
// Got it from another peer, send response (mark as forwarded)
|
|
256
|
-
this.theirRequests.delete(hashKey);
|
|
257
|
-
this.sendResponse(hash, data, true);
|
|
258
|
-
this.stats.responsesSent++;
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
// If not found, keep in theirRequests for later push
|
|
262
|
-
}
|
|
263
|
-
// Not found anywhere - stay silent, let requester timeout.
|
|
264
|
-
}
|
|
265
|
-
sendResponse(hash, data, isForwarded = false) {
|
|
266
|
-
if (!this.dataChannel || this.dataChannel.readyState !== 'open')
|
|
267
|
-
return;
|
|
268
|
-
// Track bytes sent
|
|
269
|
-
this.stats.bytesSent += data.length;
|
|
270
|
-
if (isForwarded) {
|
|
271
|
-
this.stats.bytesForwarded += data.length;
|
|
272
|
-
}
|
|
273
|
-
if (data.length <= FRAGMENT_SIZE) {
|
|
274
|
-
// Small enough - send unfragmented (backward compatible)
|
|
275
|
-
const res = createResponse(hash, data);
|
|
276
|
-
this.dataChannel.send(encodeResponse(res));
|
|
277
|
-
}
|
|
278
|
-
else {
|
|
279
|
-
// Fragment large responses
|
|
280
|
-
const totalFragments = Math.ceil(data.length / FRAGMENT_SIZE);
|
|
281
|
-
for (let i = 0; i < totalFragments; i++) {
|
|
282
|
-
const start = i * FRAGMENT_SIZE;
|
|
283
|
-
const end = Math.min(start + FRAGMENT_SIZE, data.length);
|
|
284
|
-
const fragment = data.slice(start, end);
|
|
285
|
-
const res = createFragmentResponse(hash, fragment, i, totalFragments);
|
|
286
|
-
this.dataChannel.send(encodeResponse(res));
|
|
287
|
-
this.stats.fragmentsSent++;
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
/**
|
|
292
|
-
* Handle a fragmented response - buffer and reassemble
|
|
293
|
-
* Returns assembled data when complete, null when waiting for more fragments
|
|
294
|
-
*/
|
|
295
|
-
handleFragmentResponse(res) {
|
|
296
|
-
const hashKey = hashToKey(res.h);
|
|
297
|
-
const now = Date.now();
|
|
298
|
-
this.stats.fragmentsReceived++;
|
|
299
|
-
let pending = this.pendingReassemblies.get(hashKey);
|
|
300
|
-
if (!pending) {
|
|
301
|
-
pending = {
|
|
302
|
-
hash: res.h,
|
|
303
|
-
fragments: new Map(),
|
|
304
|
-
totalExpected: res.n,
|
|
305
|
-
receivedBytes: 0,
|
|
306
|
-
firstFragmentAt: now,
|
|
307
|
-
lastFragmentAt: now,
|
|
308
|
-
};
|
|
309
|
-
this.pendingReassemblies.set(hashKey, pending);
|
|
310
|
-
}
|
|
311
|
-
// Reset request timeout on each fragment received
|
|
312
|
-
// This way we timeout if no fragment arrives for FRAGMENT_STALL_TIMEOUT
|
|
313
|
-
const pendingReq = this.ourRequests.get(hashKey);
|
|
314
|
-
if (pendingReq) {
|
|
315
|
-
clearTimeout(pendingReq.timeout);
|
|
316
|
-
pendingReq.timeout = setTimeout(() => {
|
|
317
|
-
this.ourRequests.delete(hashKey);
|
|
318
|
-
this.pendingReassemblies.delete(hashKey);
|
|
319
|
-
this.stats.fragmentTimeouts++;
|
|
320
|
-
pendingReq.resolve(null);
|
|
321
|
-
}, FRAGMENT_STALL_TIMEOUT);
|
|
322
|
-
}
|
|
323
|
-
// Store fragment if not duplicate
|
|
324
|
-
if (!pending.fragments.has(res.i)) {
|
|
325
|
-
pending.fragments.set(res.i, res.d);
|
|
326
|
-
pending.receivedBytes += res.d.length;
|
|
327
|
-
pending.lastFragmentAt = now;
|
|
328
|
-
}
|
|
329
|
-
// Check if complete
|
|
330
|
-
if (pending.fragments.size === pending.totalExpected) {
|
|
331
|
-
this.pendingReassemblies.delete(hashKey);
|
|
332
|
-
this.stats.reassembliesCompleted++;
|
|
333
|
-
return this.assembleFragments(pending);
|
|
334
|
-
}
|
|
335
|
-
return null; // Not yet complete
|
|
336
|
-
}
|
|
337
|
-
/**
|
|
338
|
-
* Assemble fragments in order into a single buffer
|
|
339
|
-
*/
|
|
340
|
-
assembleFragments(pending) {
|
|
341
|
-
const result = new Uint8Array(pending.receivedBytes);
|
|
342
|
-
let offset = 0;
|
|
343
|
-
for (let i = 0; i < pending.totalExpected; i++) {
|
|
344
|
-
const fragment = pending.fragments.get(i);
|
|
345
|
-
result.set(fragment, offset);
|
|
346
|
-
offset += fragment.length;
|
|
347
|
-
}
|
|
348
|
-
return result;
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* Clean up stale reassemblies (stalled or timed out)
|
|
352
|
-
*/
|
|
353
|
-
cleanupStaleReassemblies() {
|
|
354
|
-
const now = Date.now();
|
|
355
|
-
for (const [key, pending] of this.pendingReassemblies) {
|
|
356
|
-
const stallTime = now - pending.lastFragmentAt;
|
|
357
|
-
const totalTime = now - pending.firstFragmentAt;
|
|
358
|
-
if (stallTime > FRAGMENT_STALL_TIMEOUT || totalTime > FRAGMENT_TOTAL_TIMEOUT) {
|
|
359
|
-
this.pendingReassemblies.delete(key);
|
|
360
|
-
this.stats.fragmentTimeouts++;
|
|
361
|
-
this.log('Fragment reassembly timed out:', key.slice(0, 16), `stall=${stallTime}ms, total=${totalTime}ms, fragments=${pending.fragments.size}/${pending.totalExpected}`);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
// Memory cap enforcement - evict oldest if over limit
|
|
365
|
-
if (this.pendingReassemblies.size > MAX_PENDING_REASSEMBLIES) {
|
|
366
|
-
const oldest = [...this.pendingReassemblies.entries()]
|
|
367
|
-
.sort((a, b) => a[1].firstFragmentAt - b[1].firstFragmentAt)[0];
|
|
368
|
-
if (oldest) {
|
|
369
|
-
this.pendingReassemblies.delete(oldest[0]);
|
|
370
|
-
this.stats.fragmentTimeouts++;
|
|
371
|
-
this.log('Fragment reassembly evicted (memory cap):', oldest[0].slice(0, 16));
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* Request data by hash from this peer
|
|
377
|
-
* @param htl Hops To Live - decremented before sending
|
|
378
|
-
*/
|
|
379
|
-
async request(hash, htl = MAX_HTL) {
|
|
380
|
-
if (!this.dataChannel || this.dataChannel.readyState !== 'open') {
|
|
381
|
-
return null;
|
|
382
|
-
}
|
|
383
|
-
const hashKey = hashToKey(hash);
|
|
384
|
-
// Check if we already have a pending request for this hash
|
|
385
|
-
const existing = this.ourRequests.get(hashKey);
|
|
386
|
-
if (existing) {
|
|
387
|
-
// Return a new promise that resolves when the existing one does
|
|
388
|
-
return new Promise((resolve) => {
|
|
389
|
-
const originalResolve = existing.resolve;
|
|
390
|
-
existing.resolve = (data) => {
|
|
391
|
-
originalResolve(data);
|
|
392
|
-
resolve(data);
|
|
393
|
-
};
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
// Decrement HTL before sending (Freenet-style per-peer decrement)
|
|
397
|
-
const sendHTL = decrementHTL(htl, this.htlConfig);
|
|
398
|
-
this.stats.requestsSent++;
|
|
399
|
-
return new Promise((resolve) => {
|
|
400
|
-
const timeout = setTimeout(() => {
|
|
401
|
-
this.ourRequests.delete(hashKey);
|
|
402
|
-
resolve(null);
|
|
403
|
-
}, this.requestTimeout);
|
|
404
|
-
this.ourRequests.set(hashKey, { hash, resolve, timeout });
|
|
405
|
-
const req = createRequest(hash, sendHTL);
|
|
406
|
-
this.dataChannel.send(encodeRequest(req));
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
/**
|
|
410
|
-
* Get per-peer statistics
|
|
411
|
-
*/
|
|
412
|
-
getStats() {
|
|
413
|
-
return { ...this.stats };
|
|
414
|
-
}
|
|
415
|
-
/**
|
|
416
|
-
* Send data to this peer for a hash they previously requested
|
|
417
|
-
* Returns true if this peer had requested this hash
|
|
418
|
-
*/
|
|
419
|
-
sendData(hash, data) {
|
|
420
|
-
const hashKey = hashToKey(hash);
|
|
421
|
-
const theirReq = this.theirRequests.get(hashKey);
|
|
422
|
-
if (!theirReq) {
|
|
423
|
-
return false;
|
|
424
|
-
}
|
|
425
|
-
this.theirRequests.delete(hashKey);
|
|
426
|
-
// Send response with data
|
|
427
|
-
this.sendResponse(hash, data);
|
|
428
|
-
this.stats.responsesSent++;
|
|
429
|
-
this.log('Sent data for hash:', hashKey.slice(0, 16));
|
|
430
|
-
return true;
|
|
431
|
-
}
|
|
432
|
-
/**
|
|
433
|
-
* Check if this peer has requested a hash
|
|
434
|
-
*/
|
|
435
|
-
hasRequested(hash) {
|
|
436
|
-
return this.theirRequests.has(hashToKey(hash));
|
|
437
|
-
}
|
|
438
|
-
/**
|
|
439
|
-
* Get count of pending requests from this peer
|
|
440
|
-
*/
|
|
441
|
-
getTheirRequestCount() {
|
|
442
|
-
return this.theirRequests.size;
|
|
443
|
-
}
|
|
444
|
-
/**
|
|
445
|
-
* Initiate connection (create offer)
|
|
446
|
-
* Uses perfect negotiation pattern - both peers can call this
|
|
447
|
-
*/
|
|
448
|
-
async connect() {
|
|
449
|
-
// Create data channel if we don't have one yet
|
|
450
|
-
if (!this.dataChannel) {
|
|
451
|
-
// Unordered for better performance - protocol is stateless (each message self-describes)
|
|
452
|
-
this.dataChannel = this.pc.createDataChannel('hashtree', { ordered: false });
|
|
453
|
-
this.setupDataChannel(this.dataChannel);
|
|
454
|
-
}
|
|
455
|
-
try {
|
|
456
|
-
this.makingOffer = true;
|
|
457
|
-
const offer = await this.pc.createOffer();
|
|
458
|
-
await this.pc.setLocalDescription(offer);
|
|
459
|
-
await this.sendSignaling({
|
|
460
|
-
type: 'offer',
|
|
461
|
-
sdp: offer.sdp,
|
|
462
|
-
targetPeerId: this.peerId,
|
|
463
|
-
peerId: this.myPeerId,
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
finally {
|
|
467
|
-
this.makingOffer = false;
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
/**
|
|
471
|
-
* Handle incoming signaling message
|
|
472
|
-
* Implements perfect negotiation pattern for collision handling
|
|
473
|
-
*/
|
|
474
|
-
async handleSignaling(msg) {
|
|
475
|
-
if (msg.type === 'offer') {
|
|
476
|
-
// Perfect negotiation: check for offer collision
|
|
477
|
-
const offerCollision = this.makingOffer ||
|
|
478
|
-
(this.pc.signalingState !== 'stable' && this.pc.signalingState !== 'closed');
|
|
479
|
-
this.ignoreOffer = !this.isPolite && offerCollision;
|
|
480
|
-
if (this.ignoreOffer) {
|
|
481
|
-
this.log('Ignoring offer collision (impolite peer)');
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
484
|
-
// If we're polite and have a collision, we rollback and accept their offer
|
|
485
|
-
if (offerCollision) {
|
|
486
|
-
this.log('Rolling back local offer (polite peer)');
|
|
487
|
-
}
|
|
488
|
-
// Construct RTCSessionDescriptionInit from flat sdp field
|
|
489
|
-
await this.pc.setRemoteDescription(new RTCSessionDescription({ type: 'offer', sdp: msg.sdp }));
|
|
490
|
-
await this.processQueuedCandidates();
|
|
491
|
-
const answer = await this.pc.createAnswer();
|
|
492
|
-
await this.pc.setLocalDescription(answer);
|
|
493
|
-
await this.sendSignaling({
|
|
494
|
-
type: 'answer',
|
|
495
|
-
sdp: answer.sdp,
|
|
496
|
-
targetPeerId: this.peerId,
|
|
497
|
-
peerId: this.myPeerId,
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
else if (msg.type === 'answer') {
|
|
501
|
-
// Ignore answer if we're not expecting one (e.g., after rollback)
|
|
502
|
-
if (this.pc.signalingState === 'stable') {
|
|
503
|
-
this.log('Ignoring unexpected answer in stable state');
|
|
504
|
-
return;
|
|
505
|
-
}
|
|
506
|
-
// Construct RTCSessionDescriptionInit from flat sdp field
|
|
507
|
-
await this.pc.setRemoteDescription(new RTCSessionDescription({ type: 'answer', sdp: msg.sdp }));
|
|
508
|
-
await this.processQueuedCandidates();
|
|
509
|
-
}
|
|
510
|
-
else if (msg.type === 'candidate') {
|
|
511
|
-
// Construct RTCIceCandidateInit from flat fields
|
|
512
|
-
await this.addRemoteCandidate({
|
|
513
|
-
candidate: msg.candidate,
|
|
514
|
-
sdpMLineIndex: msg.sdpMLineIndex,
|
|
515
|
-
sdpMid: msg.sdpMid,
|
|
516
|
-
});
|
|
517
|
-
}
|
|
518
|
-
else if (msg.type === 'candidates') {
|
|
519
|
-
// Handle batched candidates
|
|
520
|
-
for (const c of msg.candidates) {
|
|
521
|
-
await this.addRemoteCandidate({
|
|
522
|
-
candidate: c.candidate,
|
|
523
|
-
sdpMLineIndex: c.sdpMLineIndex,
|
|
524
|
-
sdpMid: c.sdpMid,
|
|
525
|
-
});
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
async addRemoteCandidate(candidate) {
|
|
530
|
-
// Queue candidates if remote description not set yet
|
|
531
|
-
if (!this.pc.remoteDescription) {
|
|
532
|
-
this.queuedRemoteCandidates.push(candidate);
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
try {
|
|
536
|
-
await this.pc.addIceCandidate(new RTCIceCandidate(candidate));
|
|
537
|
-
}
|
|
538
|
-
catch (err) {
|
|
539
|
-
this.log('Failed to add ICE candidate:', err);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
async processQueuedCandidates() {
|
|
543
|
-
const candidates = this.queuedRemoteCandidates;
|
|
544
|
-
this.queuedRemoteCandidates = [];
|
|
545
|
-
for (const candidate of candidates) {
|
|
546
|
-
try {
|
|
547
|
-
await this.pc.addIceCandidate(new RTCIceCandidate(candidate));
|
|
548
|
-
}
|
|
549
|
-
catch (err) {
|
|
550
|
-
this.log('Failed to add queued ICE candidate:', err);
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
/**
|
|
555
|
-
* Close the peer connection
|
|
556
|
-
*/
|
|
557
|
-
close() {
|
|
558
|
-
if (this.candidateBatchTimeout) {
|
|
559
|
-
clearTimeout(this.candidateBatchTimeout);
|
|
560
|
-
this.candidateBatchTimeout = null;
|
|
561
|
-
}
|
|
562
|
-
// Clean up fragment reassembly
|
|
563
|
-
if (this.reassemblyCleanupInterval) {
|
|
564
|
-
clearInterval(this.reassemblyCleanupInterval);
|
|
565
|
-
this.reassemblyCleanupInterval = undefined;
|
|
566
|
-
}
|
|
567
|
-
this.pendingReassemblies.clear();
|
|
568
|
-
clearPendingRequests(this.ourRequests);
|
|
569
|
-
if (this.dataChannel) {
|
|
570
|
-
this.dataChannel.onopen = null;
|
|
571
|
-
this.dataChannel.onclose = null;
|
|
572
|
-
this.dataChannel.onmessage = null;
|
|
573
|
-
this.dataChannel.close();
|
|
574
|
-
this.dataChannel = null;
|
|
575
|
-
}
|
|
576
|
-
this.pc.onicecandidate = null;
|
|
577
|
-
this.pc.onconnectionstatechange = null;
|
|
578
|
-
this.pc.ondatachannel = null;
|
|
579
|
-
this.pc.close();
|
|
580
|
-
this.onClose();
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
//# sourceMappingURL=peer.js.map
|
package/dist/webrtc/peer.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"peer.js","sourceRoot":"","sources":["../../src/webrtc/peer.ts"],"names":[],"mappings":"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"}
|