diff --git a/test-connect.js b/test-connect.js index 401c90c..894936c 100644 --- a/test-connect.js +++ b/test-connect.js @@ -15,7 +15,7 @@ * - Build tools (python, make, g++) */ -import { Rondevu, RondevuSignaler, NodeCryptoAdapter } from '@xtr-dev/rondevu-client' +import { Rondevu, NodeCryptoAdapter } from '@xtr-dev/rondevu-client' // Import wrtc let wrtc @@ -40,22 +40,6 @@ const TARGET_USER = 'bas' const SERVICE_FQN = `chat:2.0.0@${TARGET_USER}` 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() { console.log('šŸš€ Rondevu Test Script') console.log('='.repeat(50)) @@ -73,174 +57,80 @@ async function main() { console.log(` āœ“ Connected as: ${rondevu.getUsername()}`) console.log(` āœ“ Public key: ${rondevu.getPublicKey()?.substring(0, 20)}...`) - // 2. Discover service - console.log(`\n2. Looking for 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 + // 2. Connect to service (automatic setup) + console.log(`\n2. Connecting to service: ${SERVICE_FQN}`) let identified = false - // Function to setup data channel handlers - const setupDataChannel = (channel) => { - dc = channel + const connection = await rondevu.connectToService({ + serviceFqn: SERVICE_FQN, + onConnection: ({ dc, peerUsername }) => { + console.log(`āœ… Connected to @${peerUsername}`) - dc.onopen = () => { - console.log(' āœ“ Data channel opened!') - console.log(` Data channel state: ${dc.readyState}`) + // Set up message handler + dc.addEventListener('message', (event) => { + 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 - setTimeout(() => { - console.log(` Data channel state before send: ${dc.readyState}`) - if (dc.readyState !== 'open') { - console.error(` āŒ Data channel not open: ${dc.readyState}`) - return + 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!') + 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) - console.log(`šŸ“¤ Sending identify message...`) - const identifyMsg = JSON.stringify({ - type: 'identify', - from: rondevu.getUsername() - }) - console.log(` Message:`, identifyMsg) - dc.send(identifyMsg) - console.log(` āœ“ Identify message sent, bufferedAmount: ${dc.bufferedAmount}`) - }, 500) + // Send identify message after channel opens + console.log(`šŸ“¤ Sending identify message...`) + const identifyMsg = JSON.stringify({ + type: 'identify', + from: rondevu.getUsername() + }) + dc.send(identifyMsg) + console.log(` āœ“ Identify message sent`) } - - 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 - pc.onconnectionstatechange = () => { - console.log(` Connection state: ${pc.connectionState}`) - if (pc.connectionState === 'failed') { + connection.pc.onconnectionstatechange = () => { + console.log(` Connection state: ${connection.pc.connectionState}`) + if (connection.pc.connectionState === 'failed') { console.error('āŒ Connection failed') process.exit(1) } } - pc.oniceconnectionstatechange = () => { - console.log(` ICE state: ${pc.iceConnectionState}`) + connection.pc.oniceconnectionstatechange = () => { + console.log(` ICE state: ${connection.pc.iceConnectionState}`) } - console.log('\nā³ Waiting for connection...') + console.log('\nā³ Waiting for messages...') // Timeout after 30 seconds setTimeout(() => { - if (pc.connectionState !== 'connected') { + if (connection.pc.connectionState !== 'connected') { console.error('āŒ Connection timeout') process.exit(1) }