aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/go-live-test.js36
1 files changed, 32 insertions, 4 deletions
diff --git a/tools/go-live-test.js b/tools/go-live-test.js
index 82d6c7c..61e3c02 100644
--- a/tools/go-live-test.js
+++ b/tools/go-live-test.js
@@ -8,7 +8,7 @@
import puppeteer from './puppeteer.js';
import { cacheKeyFor } from '../src/wallet.js';
import { naddrEncode } from 'nostr-tools/nip19';
-import { mkdtempSync, rmSync } from 'node:fs';
+import { mkdtempSync, rmSync, readFileSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
let ok = true;
@@ -23,8 +23,17 @@ const names = Bun.serve({ port: 0, hostname: '127.0.0.1', fetch: (req) => Respon
process.env.LIVE_DATA = dir;
process.env.NAMES_URL = names.url.origin;
process.env.LIVE_BASE = `http://localhost:${PORT}/live`;
-const live = await import(process.env.LIVE_SERVER || '../../coinosv3-server/live/server.js');
-const server = Bun.serve({ port: PORT, websocket: live.websocket, fetch: async (req, srv) => {
+const LIVE_PATH = process.env.LIVE_SERVER || '../../coinosv3-server/live/server.js';
+let live = await import(LIVE_PATH);
+// each socket stays with the server (module) that took it, so a "restart"
+// (a fresh import) leaves the old connections to the old one
+const sockMod = new WeakMap();
+const websocket = {
+ open: (ws) => { sockMod.set(ws, live); live.websocket.open?.(ws); },
+ message: (ws, m) => (sockMod.get(ws) || live).websocket.message?.(ws, m),
+ close: (ws, c, r) => (sockMod.get(ws) || live).websocket.close?.(ws, c, r),
+};
+const server = Bun.serve({ port: PORT, websocket, fetch: async (req, srv) => {
const path = new URL(req.url).pathname;
if (path.startsWith('/live/')) {
if (path === '/live/ingest') try { owner = JSON.parse(atob(new URL(req.url).searchParams.get('auth'))).pubkey; } catch {}
@@ -43,7 +52,7 @@ const relayStub = (fx) => {
const Real = window.WebSocket;
window.WebSocket = function (...a) {
const ws = new Real(...a);
- if (/\/live\/ingest/.test(String(a[0]))) return ws; // the live server itself
+ if (/\/live\/ingest/.test(String(a[0]))) { (window.__ingest = window.__ingest || []).push(ws); return ws; } // the live server itself
const send = ws.send.bind(ws);
ws.send = (data) => {
try {
@@ -131,6 +140,25 @@ try {
check('the server counts the watcher', st.viewers >= 1, JSON.stringify(st));
await viewer.close();
+ console.log('\n[the server restarts mid-stream]');
+ // a fresh server, and the old one's shutdown: its streams end
+ live = await import(LIVE_PATH + '?restart=1');
+ const oldId = tag(ann, 'd');
+ const sj = `${dir}/${oldId}/stream.json`;
+ writeFileSync(sj, JSON.stringify({ ...JSON.parse(readFileSync(sj, 'utf8')), state: 'ended', ended: Date.now() }));
+ const before = (await lives(page)).length;
+ await page.evaluate(() => window.__ingest.forEach((w) => w.close()));
+ check('the app comes back as a new stream and announces it', await waitFor((n) => window.__published.filter((e) => e.kind === 30311).slice(n)
+ .some((e) => e.tags.some((x) => x[0] === 'status' && x[1] === 'live')), 40000, before));
+ const after = (await lives(page)).slice(before);
+ const again = after.find((e) => tag(e, 'status') === 'live');
+ check('...at its new address, not the dead one', again && tag(again, 'd') !== oldId && tag(again, 'streaming').includes(tag(again, 'd')), JSON.stringify(after.map((e) => [tag(e, 'd'), tag(e, 'status')])));
+ const gone = after.find((e) => tag(e, 'd') === oldId);
+ check('...the old one said to be over, with no recording', gone && tag(gone, 'status') === 'ended' && !gone.tags.some((x) => x[0] === 'recording'));
+ const pl = await (await fetch(tag(again, 'streaming'))).text();
+ check('...and the new one plays', (pl.match(/\.ts/g) || []).length >= 3, (pl.match(/\.ts/g) || []).length + ' segments');
+ check('the streamer\'s own page follows to it', await waitFor((a) => !!document.querySelector('.live-page .bc-bar'), 5000));
+
console.log('\n[the end]');
await page.evaluate(() => document.querySelector('.bc-end').click());
check('End leaves the stream\'s page', await waitFor(() => !document.querySelector('.bc-bar'), 5000));