diff options
| author | Adam Soltys <[email protected]> | 2026-10-18 09:55:40 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-18 09:55:40 -0700 |
| commit | d86f7cb039bbd4bf2873be332af278bc6372aeae (patch) | |
| tree | 522cc403f44619ba694f51953ea7578bc310eb41 /tools | |
| parent | 5869fa2ce351efa485ae6547d618a216b09a47c1 (diff) | |
| download | coinosv3-d86f7cb039bbd4bf2873be332af278bc6372aeae.tar.gz coinosv3-d86f7cb039bbd4bf2873be332af278bc6372aeae.zip | |
Answering a call no longer takes seconds: while it rings, the connection is made with the caller's offer and its routes (TURN's too) gather, and the caller's relays and TURN credentials are looked up — Answer only adds the microphone and camera and replies (3.2 s → 0.2 s on a simulated network). An open conversation warms the same for calling out. A remote signer's offer or answer waits for a direct and a relayed route or 1.5 s, not for all of them (up to 4 s).HEADmaster
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/call-test.js | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/tools/call-test.js b/tools/call-test.js index 7e9a99c..5bfa38c 100644 --- a/tools/call-test.js +++ b/tools/call-test.js @@ -14,6 +14,7 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); let ok = true; const check = (n, c, d = '') => { console.log(` ${c ? '✓' : '✗'} ${n}${d ? ' — ' + d : ''}`); if (!c) ok = false; }; const PORT = 5305; +const SLOW = +(process.env.SLOW || 0); if (!process.env.NO_BUILD && Bun.spawnSync(['bun', 'build.js']).exitCode !== 0) throw new Error('build failed'); // a small relay: keeps what isn't ephemeral, sends each event to the subscriptions it matches @@ -25,7 +26,9 @@ const server = Bun.serve({ port: PORT, fetch: async (req, srv) => { const path = new URL(req.url).pathname; if (path === '/relay') return srv.upgrade(req) ? undefined : new Response('ws', { status: 426 }); - if (path === '/live/turn') return Response.json({ iceServers: [], ttl: 600 }); // two tabs on one machine: no TURN needed + // two tabs on one machine: no TURN needed (SLOW=ms makes it, and the relay + // lookups, take as long as they do out there) + if (path === '/live/turn') { if (SLOW) await sleep(SLOW); return Response.json({ iceServers: [], ttl: 600 }); } const f = Bun.file('dist' + path); return path.includes('.') && await f.exists() ? new Response(f) : new Response(Bun.file('dist/index.html')); }, @@ -39,6 +42,7 @@ const server = Bun.serve({ port: PORT, if (!(e.kind >= 20000 && e.kind < 30000)) stored.push(e); for (const s of subs) if (s.ws.readyState === 1 && s.filters.some((f) => match({ ...f, since: undefined }, e))) s.ws.send(JSON.stringify(['EVENT', s.id, e])); } else if (m[0] === 'REQ') { + if (SLOW && m.slice(2).some((f) => (f.kinds || []).includes(10050))) { setTimeout(() => ws.send(JSON.stringify(['EOSE', m[1]])), SLOW); return; } const s = { ws, id: m[1], filters: m.slice(2) }; ws.data.subs.set(m[1], s); subs.add(s); for (const e of stored) if (s.filters.some((f) => match(f, e))) ws.send(JSON.stringify(['EVENT', m[1], e])); @@ -106,8 +110,12 @@ try { check('the caller sees it calling, their own camera on', await waitFor(A.page, () => /calling/i.test(document.querySelector('.call-overlay .call-status')?.textContent || '') && document.querySelector('video.call-local')?.videoWidth > 0, 10000)); check('the callee, on their wallet page, is rung: who, and a video call', await waitFor(B.page, () => !!document.querySelector('.call-overlay .call-accept') && /Alice Caller/.test(document.querySelector('.call-overlay').innerText) && /video call/i.test(document.querySelector('.call-overlay').innerText), 15000)); check('everything went as ephemeral gift wraps', kindsSeen.length > 0 && !kindsSeen.some((k) => k >= 25050 && k <= 25055) && kindsSeen.includes(21059)); + if (process.env.RING_WAIT) await sleep(+process.env.RING_WAIT); // a person reaching for the phone + const tAccept = Date.now(); await B.page.evaluate(() => document.querySelector('.call-accept').click()); - check('answered: both connected, the clock running', await waitFor(A.page, () => /^\d+:\d\d$/.test(document.querySelector('.call-overlay .call-status')?.textContent || ''), 20000) && await waitFor(B.page, () => /^\d+:\d\d$/.test(document.querySelector('.call-overlay .call-status')?.textContent || ''), 5000)); + await waitFor(B.page, () => /^\d+:\d\d$/.test(document.querySelector('.call-overlay .call-status')?.textContent || ''), 20000); + const answerMs = Date.now() - tAccept; + check('answered: both connected, the clock running (' + answerMs + ' ms from Answer)', await waitFor(A.page, () => /^\d+:\d\d$/.test(document.querySelector('.call-overlay .call-status')?.textContent || ''), 20000) && await waitFor(B.page, () => /^\d+:\d\d$/.test(document.querySelector('.call-overlay .call-status')?.textContent || ''), 5000)); await sleep(1500); const ma = await media(A.page), mb = await media(B.page); check('each sees the other\'s picture and gets their sound', ma.video && ma.audio && mb.video && mb.audio, JSON.stringify({ ma, mb })); |
