From b3b1751f6335164236d2bd092a2f583717726fbc Mon Sep 17 00:00:00 2001 From: Bas van den Aakster Date: Sun, 14 Dec 2025 14:28:57 +0100 Subject: [PATCH] Fix duplicate answer bug - update timestamp before processing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: When setRemoteDescription failed, lastPollTimestamp was never updated, causing the server to return the same answer repeatedly. Solution: 1. Update lastPollTimestamp BEFORE processing answers 2. Calculate max timestamp from all received answers upfront 3. Don't throw on setRemoteDescription errors - just log and continue 4. This ensures we advance the timestamp even if processing fails This prevents the infinite loop of: - Poll returns answer - Processing fails - Timestamp not updated - Next poll returns same answer - Repeat Now the timestamp advances regardless of processing success, preventing duplicate answer fetches from the server. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/rondevu.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/rondevu.ts b/src/rondevu.ts index afeb403..f101f5c 100644 --- a/src/rondevu.ts +++ b/src/rondevu.ts @@ -645,6 +645,12 @@ export class Rondevu extends EventEmitter { try { const result = await this.api.poll(this.lastPollTimestamp) + // Update timestamp FIRST to prevent re-fetching same answers if processing fails + if (result.answers.length > 0) { + const maxAnswerTimestamp = Math.max(...result.answers.map(a => a.answeredAt)) + this.lastPollTimestamp = Math.max(this.lastPollTimestamp, maxAnswerTimestamp) + } + // Process answers for (const answer of result.answers) { const activeOffer = this.activeOffers.get(answer.offerId) @@ -660,7 +666,6 @@ export class Rondevu extends EventEmitter { sdp: answer.sdp }) - this.lastPollTimestamp = answer.answeredAt this.emit('offer:answered', answer.offerId, answer.answererId) // Create replacement offer @@ -668,7 +673,8 @@ export class Rondevu extends EventEmitter { } catch (err) { // If setRemoteDescription fails, reset the answered flag activeOffer.answered = false - throw err + this.debug(`Failed to set remote description for offer ${answer.offerId}:`, err) + // Don't throw - continue processing other answers } } }