mirror of
https://github.com/xtr-dev/rondevu-client.git
synced 2025-12-18 22:53:23 +00:00
v0.19.0: Internal refactoring for improved maintainability
Internal improvements (100% backward compatible): - Extract OfferPool class from Rondevu for offer lifecycle management - Consolidate ICE polling logic into base RondevuConnection class (removes ~86 lines of duplicate code) - Add AsyncLock utility for race-free concurrent operations - Disable reconnection for offerer connections (offers are ephemeral) - Fix compilation with abstract method implementations Architecture improvements: - rondevu.ts: Reduced complexity by extracting OfferPool - connection.ts: Added consolidated pollIceCandidates() implementation - offerer-connection.ts: Force reconnectEnabled: false in constructor - answerer-connection.ts: Implement abstract methods from base class New files: - src/async-lock.ts: Mutual exclusion primitive for async operations - src/offer-pool.ts: Manages WebRTC offer lifecycle independently 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -329,6 +329,73 @@ export abstract class RondevuConnection extends EventEmitter<ConnectionEventMap>
|
||||
this.emit('ice:polling:stopped')
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API instance - subclasses must provide
|
||||
*/
|
||||
protected abstract getApi(): any
|
||||
|
||||
/**
|
||||
* Get the service FQN - subclasses must provide
|
||||
*/
|
||||
protected abstract getServiceFqn(): string
|
||||
|
||||
/**
|
||||
* Get the offer ID - subclasses must provide
|
||||
*/
|
||||
protected abstract getOfferId(): string
|
||||
|
||||
/**
|
||||
* Get the ICE candidate role this connection should accept.
|
||||
* Returns null for no filtering (offerer), or specific role (answerer accepts 'offerer').
|
||||
*/
|
||||
protected abstract getIceCandidateRole(): 'offerer' | null
|
||||
|
||||
/**
|
||||
* Poll for remote ICE candidates (consolidated implementation)
|
||||
* Subclasses implement getIceCandidateRole() to specify filtering
|
||||
*/
|
||||
protected pollIceCandidates(): void {
|
||||
const acceptRole = this.getIceCandidateRole()
|
||||
const api = this.getApi()
|
||||
const serviceFqn = this.getServiceFqn()
|
||||
const offerId = this.getOfferId()
|
||||
|
||||
api
|
||||
.getOfferIceCandidates(serviceFqn, offerId, this.lastIcePollTime)
|
||||
.then((result: any) => {
|
||||
if (result.candidates.length > 0) {
|
||||
this.debug(`Received ${result.candidates.length} remote ICE candidates`)
|
||||
|
||||
for (const iceCandidate of result.candidates) {
|
||||
// Filter by role if specified (answerer only filters for 'offerer')
|
||||
if (acceptRole !== null && iceCandidate.role !== acceptRole) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (iceCandidate.candidate && this.pc) {
|
||||
const candidate = iceCandidate.candidate
|
||||
this.pc
|
||||
.addIceCandidate(new RTCIceCandidate(candidate))
|
||||
.then(() => {
|
||||
this.emit('ice:candidate:remote', new RTCIceCandidate(candidate))
|
||||
})
|
||||
.catch((error) => {
|
||||
this.debug('Failed to add ICE candidate:', error)
|
||||
})
|
||||
}
|
||||
|
||||
// Update last poll time
|
||||
if (iceCandidate.createdAt > this.lastIcePollTime) {
|
||||
this.lastIcePollTime = iceCandidate.createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
this.debug('Failed to poll ICE candidates:', error)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Start connection timeout
|
||||
*/
|
||||
@@ -562,6 +629,5 @@ export abstract class RondevuConnection extends EventEmitter<ConnectionEventMap>
|
||||
|
||||
// Abstract methods to be implemented by subclasses
|
||||
protected abstract onLocalIceCandidate(candidate: RTCIceCandidate): void
|
||||
protected abstract pollIceCandidates(): void
|
||||
protected abstract attemptReconnect(): void
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user