Something went wrong. Try again.
Demo comparing html-over-the-wire w/ WS and SSE.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104import { spawn } from 'node:child_process'import path from 'node:path'import { fileURLToPath } from 'node:url'import { createDelayProxy } from '../src/tcp-delay.js'
const __dirname = path.dirname(fileURLToPath(import.meta.url))export const ROOT = path.join(__dirname, '..')
export const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
export function pct(sorted, p) { if (!sorted.length) return NaN const i = Math.min(sorted.length - 1, Math.max(0, Math.ceil((p / 100) * sorted.length) - 1)) return sorted[i]}
export function summarize(samples) { const s = [...samples].sort((a, b) => a - b) const mean = s.reduce((a, b) => a + b, 0) / (s.length || 1) return { n: s.length, mean: +mean.toFixed(2), p50: +pct(s, 50).toFixed(2), p95: +pct(s, 95).toFixed(2), p99: +pct(s, 99).toFixed(2), max: +(s[s.length - 1] ?? NaN).toFixed(2), }}
export async function startServer(opts) { // Ports come from the OS (bind 0) and are read back off the ready line, so // an aborted run can never poison the next one with EADDRINUSE. const argv = [ '--expose-gc', path.join(ROOT, 'src/server.js'), '--arch', opts.arch, '--compress', opts.compress ?? 'none', '--mode', opts.mode ?? 'narrow', ] if (opts.tls) argv.push('--tls') if (opts.h1) argv.push('--h1') if (opts.lgwin) argv.push('--lgwin', String(opts.lgwin)) if (opts.ws_no_context_takeover) argv.push('--ws-no-context-takeover')
const proc = spawn(process.execPath, argv, { stdio: ['ignore', 'pipe', 'inherit'], env: { ...process.env, NODE_OPTIONS: '' }, }) const { port, controlPort } = await new Promise((resolve, reject) => { const t = setTimeout(() => reject(new Error('server start timeout')), 10000) proc.stdout.on('data', (d) => { const line = d.toString() const m = line.match(/port=(\d+) control=(\d+)/) if (m) { clearTimeout(t) resolve({ port: Number(m[1]), controlPort: Number(m[2]) }) } }) proc.on('exit', (c) => reject(new Error(`server exited ${c}`))) })
return { port, controlPort, proc, async stats() { const res = await fetch(`http://127.0.0.1:${controlPort}/stats`) return res.json() }, async reset() { await fetch(`http://127.0.0.1:${controlPort}/reset`) }, async stop() { try { await fetch(`http://127.0.0.1:${controlPort}/shutdown`) } catch {} await sleep(120) if (!proc.killed) proc.kill('SIGKILL') }, }}
export async function startProxy({ targetPort, owdMs, jitterMs = 0 }) { const proxy = createDelayProxy({ listenPort: 0, targetPort, owdMs, jitterMs }) const listenPort = await proxy.listen() return { ...proxy, port: listenPort }}
export function fmtBytes(n) { if (n < 1024) return `${n} B` if (n < 1048576) return `${(n / 1024).toFixed(1)} KB` return `${(n / 1048576).toFixed(2)} MB`}
export function table(rows, cols) { const widths = cols.map((c) => Math.max(c.label.length, ...rows.map((r) => String(c.get(r) ?? '').length)), ) const line = (cells) => cells.map((c, i) => String(c).padEnd(widths[i])).join(' ') const out = [line(cols.map((c) => c.label)), line(widths.map((w) => '─'.repeat(w)))] for (const r of rows) out.push(line(cols.map((c) => c.get(r) ?? ''))) return out.join('\n')}