mirror of
https://github.com/xtr-dev/rondevu-client.git
synced 2025-12-13 04:13:25 +00:00
Refactor connectToService() method for better maintainability
Break down 129-line method into focused helper methods: New private methods: - resolveServiceFqn(): Determines full FQN from various input options Handles direct FQN, service+username, or discovery mode - startIcePolling(): Manages remote ICE candidate polling Encapsulates polling logic and interval management Benefits: - connectToService() reduced from 129 to ~98 lines - Each method has single responsibility - Easier to test and maintain - Better code readability with clear method names - Reusable components for future features 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -551,6 +551,57 @@ export class Rondevu {
|
|||||||
this.activeOffers.clear()
|
this.activeOffers.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the full service FQN from various input options
|
||||||
|
* Supports direct FQN, service+username, or service discovery
|
||||||
|
*/
|
||||||
|
private async resolveServiceFqn(options: ConnectToServiceOptions): Promise<string> {
|
||||||
|
const { serviceFqn, service, username } = options
|
||||||
|
|
||||||
|
if (serviceFqn) {
|
||||||
|
return serviceFqn
|
||||||
|
} else if (service && username) {
|
||||||
|
return `${service}@${username}`
|
||||||
|
} else if (service) {
|
||||||
|
// Discovery mode - get random service
|
||||||
|
this.debug(`Discovering service: ${service}`)
|
||||||
|
const discovered = await this.discoverService(service)
|
||||||
|
return discovered.serviceFqn
|
||||||
|
} else {
|
||||||
|
throw new Error('Either serviceFqn or service must be provided')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start polling for remote ICE candidates
|
||||||
|
* Returns the polling interval ID
|
||||||
|
*/
|
||||||
|
private startIcePolling(
|
||||||
|
pc: RTCPeerConnection,
|
||||||
|
serviceFqn: string,
|
||||||
|
offerId: string
|
||||||
|
): ReturnType<typeof setInterval> {
|
||||||
|
let lastIceTimestamp = 0
|
||||||
|
|
||||||
|
return setInterval(async () => {
|
||||||
|
try {
|
||||||
|
const result = await this.api.getOfferIceCandidates(
|
||||||
|
serviceFqn,
|
||||||
|
offerId,
|
||||||
|
lastIceTimestamp
|
||||||
|
)
|
||||||
|
for (const item of result.candidates) {
|
||||||
|
if (item.candidate) {
|
||||||
|
await pc.addIceCandidate(new RTCIceCandidate(item.candidate))
|
||||||
|
lastIceTimestamp = item.createdAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[Rondevu] Failed to poll ICE candidates:', err)
|
||||||
|
}
|
||||||
|
}, Rondevu.POLLING_INTERVAL_MS)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Automatically connect to a service (answerer side)
|
* Automatically connect to a service (answerer side)
|
||||||
* Handles the entire connection flow: discovery, WebRTC setup, answer exchange, ICE candidates
|
* Handles the entire connection flow: discovery, WebRTC setup, answer exchange, ICE candidates
|
||||||
@@ -577,34 +628,21 @@ export class Rondevu {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
async connectToService(options: ConnectToServiceOptions): Promise<ConnectionContext> {
|
async connectToService(options: ConnectToServiceOptions): Promise<ConnectionContext> {
|
||||||
const { serviceFqn, service, username, onConnection, rtcConfig } = options
|
const { onConnection, rtcConfig } = options
|
||||||
|
|
||||||
// Validate inputs
|
// Validate inputs
|
||||||
if (serviceFqn !== undefined && typeof serviceFqn === 'string' && !serviceFqn.trim()) {
|
if (options.serviceFqn !== undefined && typeof options.serviceFqn === 'string' && !options.serviceFqn.trim()) {
|
||||||
throw new Error('serviceFqn cannot be empty')
|
throw new Error('serviceFqn cannot be empty')
|
||||||
}
|
}
|
||||||
if (service !== undefined && typeof service === 'string' && !service.trim()) {
|
if (options.service !== undefined && typeof options.service === 'string' && !options.service.trim()) {
|
||||||
throw new Error('service cannot be empty')
|
throw new Error('service cannot be empty')
|
||||||
}
|
}
|
||||||
if (username !== undefined && typeof username === 'string' && !username.trim()) {
|
if (options.username !== undefined && typeof options.username === 'string' && !options.username.trim()) {
|
||||||
throw new Error('username cannot be empty')
|
throw new Error('username cannot be empty')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the full service FQN
|
// Determine the full service FQN
|
||||||
let fqn: string
|
const fqn = await this.resolveServiceFqn(options)
|
||||||
if (serviceFqn) {
|
|
||||||
fqn = serviceFqn
|
|
||||||
} else if (service && username) {
|
|
||||||
fqn = `${service}@${username}`
|
|
||||||
} else if (service) {
|
|
||||||
// Discovery mode - get random service
|
|
||||||
this.debug(`Discovering service: ${service}`)
|
|
||||||
const discovered = await this.discoverService(service)
|
|
||||||
fqn = discovered.serviceFqn
|
|
||||||
} else {
|
|
||||||
throw new Error('Either serviceFqn or service must be provided')
|
|
||||||
}
|
|
||||||
|
|
||||||
this.debug(`Connecting to service: ${fqn}`)
|
this.debug(`Connecting to service: ${fqn}`)
|
||||||
|
|
||||||
// 1. Get service offer
|
// 1. Get service offer
|
||||||
@@ -631,24 +669,7 @@ export class Rondevu {
|
|||||||
this.setupIceCandidateHandler(pc, serviceData.serviceFqn, serviceData.offerId)
|
this.setupIceCandidateHandler(pc, serviceData.serviceFqn, serviceData.offerId)
|
||||||
|
|
||||||
// 5. Poll for remote ICE candidates
|
// 5. Poll for remote ICE candidates
|
||||||
let lastIceTimestamp = 0
|
const icePollInterval = this.startIcePolling(pc, serviceData.serviceFqn, serviceData.offerId)
|
||||||
const icePollInterval = setInterval(async () => {
|
|
||||||
try {
|
|
||||||
const result = await this.api.getOfferIceCandidates(
|
|
||||||
serviceData.serviceFqn,
|
|
||||||
serviceData.offerId,
|
|
||||||
lastIceTimestamp
|
|
||||||
)
|
|
||||||
for (const item of result.candidates) {
|
|
||||||
if (item.candidate) {
|
|
||||||
await pc.addIceCandidate(new RTCIceCandidate(item.candidate))
|
|
||||||
lastIceTimestamp = item.createdAt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('[Rondevu] Failed to poll ICE candidates:', err)
|
|
||||||
}
|
|
||||||
}, Rondevu.POLLING_INTERVAL_MS)
|
|
||||||
|
|
||||||
// 6. Set remote description
|
// 6. Set remote description
|
||||||
await pc.setRemoteDescription({
|
await pc.setRemoteDescription({
|
||||||
|
|||||||
Reference in New Issue
Block a user