mirror of
https://github.com/xtr-dev/rondevu-demo.git
synced 2025-12-15 12:33:23 +00:00
Remove RondevuSignaler usage and simplify test-connect.js
- Use connectToService() for automatic connection setup - Remove manual WebRTC setup (~120 lines reduced to ~60 lines) - Much simpler and cleaner code 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
220
test-connect.js
220
test-connect.js
@@ -15,7 +15,7 @@
|
|||||||
* - Build tools (python, make, g++)
|
* - Build tools (python, make, g++)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Rondevu, RondevuSignaler, NodeCryptoAdapter } from '@xtr-dev/rondevu-client'
|
import { Rondevu, NodeCryptoAdapter } from '@xtr-dev/rondevu-client'
|
||||||
|
|
||||||
// Import wrtc
|
// Import wrtc
|
||||||
let wrtc
|
let wrtc
|
||||||
@@ -40,22 +40,6 @@ const TARGET_USER = 'bas'
|
|||||||
const SERVICE_FQN = `chat:2.0.0@${TARGET_USER}`
|
const SERVICE_FQN = `chat:2.0.0@${TARGET_USER}`
|
||||||
const MESSAGE = 'hello'
|
const MESSAGE = 'hello'
|
||||||
|
|
||||||
// TURN server configuration for manual RTCPeerConnection setup
|
|
||||||
// Note: Answerer uses manual RTCPeerConnection, not automatic offer management
|
|
||||||
const RTC_CONFIG = {
|
|
||||||
iceServers: [
|
|
||||||
{ urls: 'stun:57.129.61.67:3478' },
|
|
||||||
{
|
|
||||||
urls: [
|
|
||||||
'turn:57.129.61.67:3478?transport=tcp',
|
|
||||||
'turn:57.129.61.67:3478?transport=udp',
|
|
||||||
],
|
|
||||||
username: 'webrtcuser',
|
|
||||||
credential: 'supersecretpassword'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
console.log('🚀 Rondevu Test Script')
|
console.log('🚀 Rondevu Test Script')
|
||||||
console.log('='.repeat(50))
|
console.log('='.repeat(50))
|
||||||
@@ -73,174 +57,80 @@ async function main() {
|
|||||||
console.log(` ✓ Connected as: ${rondevu.getUsername()}`)
|
console.log(` ✓ Connected as: ${rondevu.getUsername()}`)
|
||||||
console.log(` ✓ Public key: ${rondevu.getPublicKey()?.substring(0, 20)}...`)
|
console.log(` ✓ Public key: ${rondevu.getPublicKey()?.substring(0, 20)}...`)
|
||||||
|
|
||||||
// 2. Discover service
|
// 2. Connect to service (automatic setup)
|
||||||
console.log(`\n2. Looking for service: ${SERVICE_FQN}`)
|
console.log(`\n2. Connecting to service: ${SERVICE_FQN}`)
|
||||||
const serviceData = await rondevu.getService(SERVICE_FQN)
|
|
||||||
console.log(` ✓ Found service from @${serviceData.username}`)
|
|
||||||
console.log(` ✓ Offer ID: ${serviceData.offerId}`)
|
|
||||||
|
|
||||||
// 3. Create peer connection
|
|
||||||
console.log('\n3. Creating WebRTC peer connection...')
|
|
||||||
const pc = new RTCPeerConnection(RTC_CONFIG)
|
|
||||||
|
|
||||||
// 4. Wait for data channel (we're the answerer, host creates the channel)
|
|
||||||
console.log('4. Waiting for data channel from host...')
|
|
||||||
let dc = null
|
|
||||||
let identified = false
|
let identified = false
|
||||||
|
|
||||||
// Function to setup data channel handlers
|
const connection = await rondevu.connectToService({
|
||||||
const setupDataChannel = (channel) => {
|
serviceFqn: SERVICE_FQN,
|
||||||
dc = channel
|
onConnection: ({ dc, peerUsername }) => {
|
||||||
|
console.log(`✅ Connected to @${peerUsername}`)
|
||||||
|
|
||||||
dc.onopen = () => {
|
// Set up message handler
|
||||||
console.log(' ✓ Data channel opened!')
|
dc.addEventListener('message', (event) => {
|
||||||
console.log(` Data channel state: ${dc.readyState}`)
|
console.log(`📥 RAW DATA:`, event.data)
|
||||||
|
try {
|
||||||
|
const msg = JSON.parse(event.data)
|
||||||
|
console.log(`📥 Parsed message:`, JSON.stringify(msg, null, 2))
|
||||||
|
|
||||||
// Longer delay to ensure both sides are ready
|
if (msg.type === 'identify_ack' && !identified) {
|
||||||
setTimeout(() => {
|
identified = true
|
||||||
console.log(` Data channel state before send: ${dc.readyState}`)
|
console.log(`✅ Connection acknowledged by @${msg.from}`)
|
||||||
if (dc.readyState !== 'open') {
|
|
||||||
console.error(` ❌ Data channel not open: ${dc.readyState}`)
|
// Now send the actual chat message
|
||||||
return
|
console.log(`📤 Sending chat message: "${MESSAGE}"`)
|
||||||
|
dc.send(JSON.stringify({
|
||||||
|
type: 'message',
|
||||||
|
text: MESSAGE
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Keep connection open longer to see if we get a response
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log('\n✅ Test completed successfully!')
|
||||||
|
connection.dc.close()
|
||||||
|
connection.pc.close()
|
||||||
|
process.exit(0)
|
||||||
|
}, 5000)
|
||||||
|
} else if (msg.type === 'message') {
|
||||||
|
console.log(`💬 @${msg.from || 'peer'}: ${msg.text}`)
|
||||||
|
} else {
|
||||||
|
console.log(`📥 Unknown message type: ${msg.type}`)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`📥 Parse error:`, err.message)
|
||||||
|
console.log(`📥 Raw data was:`, event.data)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Send identify message (demo protocol)
|
// Send identify message after channel opens
|
||||||
console.log(`📤 Sending identify message...`)
|
console.log(`📤 Sending identify message...`)
|
||||||
const identifyMsg = JSON.stringify({
|
const identifyMsg = JSON.stringify({
|
||||||
type: 'identify',
|
type: 'identify',
|
||||||
from: rondevu.getUsername()
|
from: rondevu.getUsername()
|
||||||
})
|
})
|
||||||
console.log(` Message:`, identifyMsg)
|
dc.send(identifyMsg)
|
||||||
dc.send(identifyMsg)
|
console.log(` ✓ Identify message sent`)
|
||||||
console.log(` ✓ Identify message sent, bufferedAmount: ${dc.bufferedAmount}`)
|
|
||||||
}, 500)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dc.onclose = () => {
|
|
||||||
console.log(' ❌ Data channel closed!')
|
|
||||||
}
|
|
||||||
|
|
||||||
dc.onmessage = (event) => {
|
|
||||||
console.log(`📥 RAW DATA:`, event.data)
|
|
||||||
try {
|
|
||||||
const msg = JSON.parse(event.data)
|
|
||||||
console.log(`📥 Parsed message:`, JSON.stringify(msg, null, 2))
|
|
||||||
|
|
||||||
if (msg.type === 'identify_ack' && !identified) {
|
|
||||||
identified = true
|
|
||||||
console.log(`✅ Connection acknowledged by @${msg.from}`)
|
|
||||||
|
|
||||||
// Now send the actual chat message
|
|
||||||
console.log(`📤 Sending chat message: "${MESSAGE}"`)
|
|
||||||
dc.send(JSON.stringify({
|
|
||||||
type: 'message',
|
|
||||||
text: MESSAGE
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Keep connection open longer to see if we get a response
|
|
||||||
setTimeout(() => {
|
|
||||||
console.log('\n✅ Test completed successfully!')
|
|
||||||
dc.close()
|
|
||||||
pc.close()
|
|
||||||
process.exit(0)
|
|
||||||
}, 5000)
|
|
||||||
} else if (msg.type === 'message') {
|
|
||||||
console.log(`💬 @${msg.from || 'peer'}: ${msg.text}`)
|
|
||||||
} else {
|
|
||||||
console.log(`📥 Unknown message type: ${msg.type}`)
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log(`📥 Parse error:`, err.message)
|
|
||||||
console.log(`📥 Raw data was:`, event.data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dc.onerror = (error) => {
|
|
||||||
console.error('❌ Data channel error:', error)
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive data channel from host (we're the answerer)
|
|
||||||
pc.ondatachannel = (event) => {
|
|
||||||
console.log(' ✓ Data channel received from host!')
|
|
||||||
setupDataChannel(event.channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. Set up ICE candidate exchange FIRST
|
|
||||||
console.log('5. Setting up ICE candidate exchange...')
|
|
||||||
|
|
||||||
// Send our ICE candidates
|
|
||||||
pc.onicecandidate = async (event) => {
|
|
||||||
if (event.candidate) {
|
|
||||||
console.log(' 📤 Sending ICE candidate')
|
|
||||||
try {
|
|
||||||
// wrtc doesn't have toJSON, manually create the object
|
|
||||||
const candidateInit = {
|
|
||||||
candidate: event.candidate.candidate,
|
|
||||||
sdpMLineIndex: event.candidate.sdpMLineIndex,
|
|
||||||
sdpMid: event.candidate.sdpMid,
|
|
||||||
usernameFragment: event.candidate.usernameFragment
|
|
||||||
}
|
|
||||||
await rondevu.addOfferIceCandidates(
|
|
||||||
serviceData.serviceFqn,
|
|
||||||
serviceData.offerId,
|
|
||||||
[candidateInit]
|
|
||||||
)
|
|
||||||
} catch (err) {
|
|
||||||
console.error(' ❌ Failed to send ICE candidate:', err.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start polling for remote ICE candidates
|
|
||||||
const signaler = new RondevuSignaler(rondevu, SERVICE_FQN, TARGET_USER)
|
|
||||||
signaler.offerId = serviceData.offerId
|
|
||||||
signaler.serviceFqn = serviceData.serviceFqn
|
|
||||||
|
|
||||||
signaler.addListener((candidate) => {
|
|
||||||
console.log(' 📥 Received ICE candidate')
|
|
||||||
pc.addIceCandidate(candidate)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 6. Set remote offer
|
|
||||||
console.log('6. Setting remote offer...')
|
|
||||||
await pc.setRemoteDescription({ type: 'offer', sdp: serviceData.sdp })
|
|
||||||
console.log(' ✓ Remote offer set')
|
|
||||||
|
|
||||||
// 7. Create and set local answer (this triggers ICE gathering)
|
|
||||||
console.log('7. Creating answer...')
|
|
||||||
const answer = await pc.createAnswer()
|
|
||||||
await pc.setLocalDescription(answer)
|
|
||||||
console.log(' ✓ Local answer set')
|
|
||||||
|
|
||||||
// 8. Send answer to server
|
|
||||||
console.log('8. Sending answer to signaling server...')
|
|
||||||
await rondevu.postOfferAnswer(
|
|
||||||
serviceData.serviceFqn,
|
|
||||||
serviceData.offerId,
|
|
||||||
answer.sdp
|
|
||||||
)
|
|
||||||
console.log(' ✓ Answer sent')
|
|
||||||
|
|
||||||
// Monitor connection state
|
// Monitor connection state
|
||||||
pc.onconnectionstatechange = () => {
|
connection.pc.onconnectionstatechange = () => {
|
||||||
console.log(` Connection state: ${pc.connectionState}`)
|
console.log(` Connection state: ${connection.pc.connectionState}`)
|
||||||
if (pc.connectionState === 'failed') {
|
if (connection.pc.connectionState === 'failed') {
|
||||||
console.error('❌ Connection failed')
|
console.error('❌ Connection failed')
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pc.oniceconnectionstatechange = () => {
|
connection.pc.oniceconnectionstatechange = () => {
|
||||||
console.log(` ICE state: ${pc.iceConnectionState}`)
|
console.log(` ICE state: ${connection.pc.iceConnectionState}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('\n⏳ Waiting for connection...')
|
console.log('\n⏳ Waiting for messages...')
|
||||||
|
|
||||||
// Timeout after 30 seconds
|
// Timeout after 30 seconds
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (pc.connectionState !== 'connected') {
|
if (connection.pc.connectionState !== 'connected') {
|
||||||
console.error('❌ Connection timeout')
|
console.error('❌ Connection timeout')
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user