@xtr-dev/rondevu-client 0.21.8 → 0.21.9
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.
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Advanced options use sensible defaults.
|
|
7
7
|
*/
|
|
8
8
|
export interface ConnectionOptions {
|
|
9
|
-
/** Maximum time to wait for connection (ms). Default:
|
|
9
|
+
/** Maximum time to wait for connection (ms). Default: 10000 */
|
|
10
10
|
timeout?: number;
|
|
11
11
|
/** Enable automatic reconnection on failures. Default: true */
|
|
12
12
|
reconnect?: boolean;
|
|
@@ -52,6 +52,7 @@ export declare class OfferPool extends EventEmitter<OfferPoolEvents> {
|
|
|
52
52
|
private readonly debugEnabled;
|
|
53
53
|
private readonly offerCreationThrottleMs;
|
|
54
54
|
private readonly activeConnections;
|
|
55
|
+
private readonly rotatedOfferIds;
|
|
55
56
|
private readonly matchedTagsByOffer;
|
|
56
57
|
private readonly fillLock;
|
|
57
58
|
private running;
|
|
@@ -123,6 +124,11 @@ export declare class OfferPool extends EventEmitter<OfferPoolEvents> {
|
|
|
123
124
|
* Called by Rondevu when a poll:ice event is received
|
|
124
125
|
*/
|
|
125
126
|
handlePollIce(data: PollIceEvent): void;
|
|
127
|
+
/**
|
|
128
|
+
* Resolve an offerId through the rotation chain to find the current offerId
|
|
129
|
+
* Returns the final offerId or undefined if not found
|
|
130
|
+
*/
|
|
131
|
+
private resolveRotatedOfferId;
|
|
126
132
|
/**
|
|
127
133
|
* Debug logging (only if debug enabled)
|
|
128
134
|
*/
|
package/dist/core/offer-pool.js
CHANGED
|
@@ -11,6 +11,7 @@ export class OfferPool extends EventEmitter {
|
|
|
11
11
|
super();
|
|
12
12
|
// State
|
|
13
13
|
this.activeConnections = new Map();
|
|
14
|
+
this.rotatedOfferIds = new Map(); // Maps old offerId -> new offerId for late-arriving answers
|
|
14
15
|
this.matchedTagsByOffer = new Map(); // Track matchedTags from answers
|
|
15
16
|
this.fillLock = new AsyncLock();
|
|
16
17
|
this.running = false;
|
|
@@ -57,6 +58,8 @@ export class OfferPool extends EventEmitter {
|
|
|
57
58
|
connection.close();
|
|
58
59
|
}
|
|
59
60
|
this.activeConnections.clear();
|
|
61
|
+
this.rotatedOfferIds.clear();
|
|
62
|
+
this.matchedTagsByOffer.clear();
|
|
60
63
|
}
|
|
61
64
|
/**
|
|
62
65
|
* Get count of active offers
|
|
@@ -238,6 +241,8 @@ export class OfferPool extends EventEmitter {
|
|
|
238
241
|
// Update map: remove old offerId, add new offerId with same connection
|
|
239
242
|
this.activeConnections.delete(currentOfferId);
|
|
240
243
|
this.activeConnections.set(newOfferId, connection);
|
|
244
|
+
// Track rotation so late-arriving answers for old offerId can be forwarded
|
|
245
|
+
this.rotatedOfferIds.set(currentOfferId, newOfferId);
|
|
241
246
|
this.emit('connection:rotated', currentOfferId, newOfferId, connection);
|
|
242
247
|
this.debug(`Connection rotated: ${currentOfferId} → ${newOfferId}`);
|
|
243
248
|
}
|
|
@@ -268,12 +273,25 @@ export class OfferPool extends EventEmitter {
|
|
|
268
273
|
async handlePollAnswer(data) {
|
|
269
274
|
if (!this.running)
|
|
270
275
|
return;
|
|
271
|
-
|
|
276
|
+
// Find connection - check direct mapping first, then rotated offers
|
|
277
|
+
let connection = this.activeConnections.get(data.offerId);
|
|
278
|
+
let effectiveOfferId = data.offerId;
|
|
279
|
+
if (!connection) {
|
|
280
|
+
// Check if this is a late-arriving answer for a rotated offer
|
|
281
|
+
const newOfferId = this.resolveRotatedOfferId(data.offerId);
|
|
282
|
+
if (newOfferId && newOfferId !== data.offerId) {
|
|
283
|
+
connection = this.activeConnections.get(newOfferId);
|
|
284
|
+
effectiveOfferId = newOfferId;
|
|
285
|
+
if (connection) {
|
|
286
|
+
this.debug(`Late answer for rotated offer ${data.offerId} → forwarding to ${newOfferId}`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
272
290
|
if (connection) {
|
|
273
|
-
this.debug(`Processing answer for offer ${
|
|
291
|
+
this.debug(`Processing answer for offer ${effectiveOfferId}`);
|
|
274
292
|
// Store matchedTags for when connection opens
|
|
275
293
|
if (data.matchedTags) {
|
|
276
|
-
this.matchedTagsByOffer.set(
|
|
294
|
+
this.matchedTagsByOffer.set(effectiveOfferId, data.matchedTags);
|
|
277
295
|
}
|
|
278
296
|
try {
|
|
279
297
|
await connection.processAnswer(data.sdp, data.answererPublicKey);
|
|
@@ -281,7 +299,7 @@ export class OfferPool extends EventEmitter {
|
|
|
281
299
|
this.fillOffers();
|
|
282
300
|
}
|
|
283
301
|
catch (err) {
|
|
284
|
-
this.debug(`Failed to process answer for offer ${
|
|
302
|
+
this.debug(`Failed to process answer for offer ${effectiveOfferId}:`, err);
|
|
285
303
|
}
|
|
286
304
|
}
|
|
287
305
|
// Silently ignore answers for offers we don't have - they may be for other connections
|
|
@@ -293,13 +311,42 @@ export class OfferPool extends EventEmitter {
|
|
|
293
311
|
handlePollIce(data) {
|
|
294
312
|
if (!this.running)
|
|
295
313
|
return;
|
|
296
|
-
|
|
314
|
+
// Find connection - check direct mapping first, then rotated offers
|
|
315
|
+
let connection = this.activeConnections.get(data.offerId);
|
|
316
|
+
if (!connection) {
|
|
317
|
+
// Check if this is late-arriving ICE for a rotated offer
|
|
318
|
+
const newOfferId = this.resolveRotatedOfferId(data.offerId);
|
|
319
|
+
if (newOfferId && newOfferId !== data.offerId) {
|
|
320
|
+
connection = this.activeConnections.get(newOfferId);
|
|
321
|
+
if (connection) {
|
|
322
|
+
this.debug(`Late ICE for rotated offer ${data.offerId} → forwarding to ${newOfferId}`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
297
326
|
if (connection) {
|
|
298
327
|
this.debug(`Processing ${data.candidates.length} ICE candidates for offer ${data.offerId}`);
|
|
299
328
|
connection.handleRemoteIceCandidates(data.candidates);
|
|
300
329
|
}
|
|
301
330
|
// Silently ignore ICE candidates for offers we don't have
|
|
302
331
|
}
|
|
332
|
+
/**
|
|
333
|
+
* Resolve an offerId through the rotation chain to find the current offerId
|
|
334
|
+
* Returns the final offerId or undefined if not found
|
|
335
|
+
*/
|
|
336
|
+
resolveRotatedOfferId(offerId) {
|
|
337
|
+
let currentId = offerId;
|
|
338
|
+
const visited = new Set();
|
|
339
|
+
while (this.rotatedOfferIds.has(currentId)) {
|
|
340
|
+
if (visited.has(currentId)) {
|
|
341
|
+
// Circular reference - shouldn't happen but protect against it
|
|
342
|
+
this.debug(`Circular rotation detected for ${offerId}`);
|
|
343
|
+
return undefined;
|
|
344
|
+
}
|
|
345
|
+
visited.add(currentId);
|
|
346
|
+
currentId = this.rotatedOfferIds.get(currentId);
|
|
347
|
+
}
|
|
348
|
+
return currentId !== offerId ? currentId : undefined;
|
|
349
|
+
}
|
|
303
350
|
/**
|
|
304
351
|
* Debug logging (only if debug enabled)
|
|
305
352
|
*/
|
package/package.json
CHANGED