Default harness runs to unbounded and make the stream page reconnect itself

This commit is contained in:
flamingcow
2026-08-30 19:15:25 -07:00
parent 5a74fe0c76
commit 2cdeccc84d
2 changed files with 39 additions and 22 deletions
+15 -6
View File
@@ -1,6 +1,6 @@
// Runs cabletest for a fixed time, dumps the panel to png, and streams it as // Runs cabletest until interrupted or for -for, dumps the panel to png, and
// png deltas on :8080, since the machine with the display on it is not the // streams it as png deltas on :8080, since the machine with the display on it
// machine looking at it. // is not the machine looking at it.
// //
// sudo go run ./harness -for 20s -at 3s,15s -- -a enp1s0f0np0 -b enp1s0f1np1 // sudo go run ./harness -for 20s -at 3s,15s -- -a enp1s0f0np0 -b enp1s0f1np1
package main package main
@@ -35,7 +35,7 @@ const (
) )
func main() { func main() {
runFor := flag.Duration("for", 15*time.Second, "how long to let cabletest run") runFor := flag.Duration("for", 0, "how long to let cabletest run; 0 runs until interrupted")
at := flag.String("at", "", "offsets to capture the panel at, comma separated, e.g. 3s,10s") at := flag.String("at", "", "offsets to capture the panel at, comma separated, e.g. 3s,10s")
fuzzN := flag.Int("fuzz", 0, "repeat the whole lifecycle this many times; full output only for runs that fail or log module events") fuzzN := flag.Int("fuzz", 0, "repeat the whole lifecycle this many times; full output only for runs that fail or log module events")
flag.Parse() flag.Parse()
@@ -49,6 +49,11 @@ func main() {
var err error var err error
if *fuzzN > 0 { if *fuzzN > 0 {
if *runFor <= 0 {
restoreTerm()
fmt.Fprintln(os.Stderr, "fuzz needs a bounded -for")
os.Exit(1)
}
err = fuzz(*fuzzN, *runFor, flag.Args()) err = fuzz(*fuzzN, *runFor, flag.Args())
} else { } else {
err = run(*runFor, *at, os.Stdout, flag.Args()) err = run(*runFor, *at, os.Stdout, flag.Args())
@@ -122,7 +127,7 @@ func parseShots(s string, runFor time.Duration) ([]time.Duration, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("bad offset %q: %w", f, err) return nil, fmt.Errorf("bad offset %q: %w", f, err)
} }
if d < 0 || d >= runFor { if d < 0 || (runFor > 0 && d >= runFor) {
return nil, fmt.Errorf("offset %s falls outside the %s run", d, runFor) return nil, fmt.Errorf("offset %s falls outside the %s run", d, runFor)
} }
out = append(out, d) out = append(out, d)
@@ -189,12 +194,16 @@ func run(runFor time.Duration, at string, out io.Writer, args []string) error {
fmt.Printf("captured %s\n", name) fmt.Printf("captured %s\n", name)
} }
var expire <-chan time.Time
if runFor > 0 {
expire = time.After(time.Until(start.Add(runFor)))
}
select { select {
case err := <-done: case err := <-done:
return exited(start, err) return exited(start, err)
case <-sigs: case <-sigs:
return interrupted(start, pgid, done) return interrupted(start, pgid, done)
case <-time.After(time.Until(start.Add(runFor))): case <-expire:
} }
return stop(pgid, done) return stop(pgid, done)
} }
+24 -16
View File
@@ -24,23 +24,31 @@ const page = `<!doctype html>
<script> <script>
(async () => { (async () => {
const cv = document.querySelector('canvas'), g = cv.getContext('2d'); const cv = document.querySelector('canvas'), g = cv.getContext('2d');
const rd = (await fetch('frames')).body.getReader();
let buf = new Uint8Array(0);
for (;;) { for (;;) {
const {value, done} = await rd.read(); try {
if (done) return; const res = await fetch('frames');
const b = new Uint8Array(buf.length + value.length); if (res.ok) {
b.set(buf); b.set(value, buf.length); buf = b; const rd = res.body.getReader();
for (;;) { let buf = new Uint8Array(0);
if (buf.length < 12) break; for (;;) {
const dv = new DataView(buf.buffer, buf.byteOffset); const {value, done} = await rd.read();
const x = dv.getUint32(0, true), y = dv.getUint32(4, true), n = dv.getUint32(8, true); if (done) break;
if (buf.length < 12 + n) break; const b = new Uint8Array(buf.length + value.length);
const bmp = await createImageBitmap(new Blob([buf.slice(12, 12 + n)], {type: 'image/png'})); b.set(buf); b.set(value, buf.length); buf = b;
if (x === 0 && y === 0 && cv.width !== bmp.width) { cv.width = bmp.width; cv.height = bmp.height; } for (;;) {
g.drawImage(bmp, x, y); if (buf.length < 12) break;
buf = buf.slice(12 + n); const dv = new DataView(buf.buffer, buf.byteOffset);
} const x = dv.getUint32(0, true), y = dv.getUint32(4, true), n = dv.getUint32(8, true);
if (buf.length < 12 + n) break;
const bmp = await createImageBitmap(new Blob([buf.slice(12, 12 + n)], {type: 'image/png'}));
if (x === 0 && y === 0 && cv.width !== bmp.width) { cv.width = bmp.width; cv.height = bmp.height; }
g.drawImage(bmp, x, y);
buf = buf.slice(12 + n);
}
}
}
} catch (e) {}
await new Promise(r => setTimeout(r, 1000));
} }
})(); })();
</script> </script>