aboutsummaryrefslogtreecommitdiffstats
path: root/tools/call-test.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-18 09:55:40 -0700
committerAdam Soltys <[email protected]>2026-10-18 09:55:40 -0700
commitd86f7cb039bbd4bf2873be332af278bc6372aeae (patch)
tree522cc403f44619ba694f51953ea7578bc310eb41 /tools/call-test.js
parent5869fa2ce351efa485ae6547d618a216b09a47c1 (diff)
downloadcoinosv3-master.tar.gz
coinosv3-master.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/call-test.js')
-rw-r--r--tools/call-test.js12
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 }));