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)
} }
+10 -2
View File
@@ -24,11 +24,15 @@ 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(); for (;;) {
try {
const res = await fetch('frames');
if (res.ok) {
const rd = res.body.getReader();
let buf = new Uint8Array(0); let buf = new Uint8Array(0);
for (;;) { for (;;) {
const {value, done} = await rd.read(); const {value, done} = await rd.read();
if (done) return; if (done) break;
const b = new Uint8Array(buf.length + value.length); const b = new Uint8Array(buf.length + value.length);
b.set(buf); b.set(value, buf.length); buf = b; b.set(buf); b.set(value, buf.length); buf = b;
for (;;) { for (;;) {
@@ -42,6 +46,10 @@ const page = `<!doctype html>
buf = buf.slice(12 + n); buf = buf.slice(12 + n);
} }
} }
}
} catch (e) {}
await new Promise(r => setTimeout(r, 1000));
}
})(); })();
</script> </script>
` `