code wiki / _hdl_build / nx_robust_dl.nx
nx_robust_dl.nx source
↩ module page · 74 lines · 4416 B
1// nx_robust_dl.nx -- the ROBUST segment-download core (the "keep downloading, no broken fragments" engine),
2// grounded in the download-SOTA corpus (yt-dlp fragment-retries, aria2 max-tries/continue, HTTP Range resume,
3// TS sync-byte integrity, exponential backoff). Format-agnostic (HLS .ts, DASH .m4s, direct) via a fetch
4// CALLBACK, so nx_hls_get / a DASH orchestrator / the API daemon all wrap it, and the gate injects failures.
5//
6// rdl_verify -- reject a truncated/corrupt fragment BEFORE it's stitched (the anti-broken-fragment gate)
7// rdl_fetch_retry -- fetch a fragment with up to max_tries attempts + integrity-verify each + backoff
8// rdl_state_* -- a persisted done-bitmap so an interrupted download RESUMES (skips done, never holes)
9import "nx_syscalls.nx"
10
11const RDL_GENERIC: i64 = 0
12const RDL_TS: i64 = 1 // MPEG-TS: 188-byte packets, each starting with the 0x47 sync byte
13
14// ---- integrity: is this fragment WHOLE + well-formed (not truncated/garbage)? ----
15func rdl_verify_ts(bytes: *u8, len: i64) -> i64 {
16 if len <= 0 { return 0 }
17 if (len % 188) != 0 { return 0 } // a whole TS fragment is a multiple of 188 bytes
18 if (bytes[0] & 0xff) != 0x47 { return 0 } // first packet's sync byte
19 var i: i64 = 0
20 var checked: i64 = 0
21 while checked < 16 { // spot-check the first 16 packet boundaries
22 if i >= len { checked = 16 }
23 else { if (bytes[i] & 0xff) != 0x47 { return 0 } i = i + 188; checked = checked + 1 }
24 }
25 return 1
26}
27func rdl_verify(bytes: *u8, len: i64, kind: i64) -> i64 {
28 if len <= 0 { return 0 }
29 if kind == RDL_TS { return rdl_verify_ts(bytes, len) }
30 return 1 // generic (mp4/m4s/webm): non-empty is the minimum bar
31}
32
33// ---- retry: fetch one fragment reliably ----
34// fetch_fn(url, urllen, attempt, out, outcap, rctx) -> bytes fetched (<=0 = network failure). Called with the
35// attempt index so a live fetcher can add a Range header / vary. Between attempts we back off (skipped when
36// backoff_ms<=0, e.g. in the gate). Returns the verified byte count, or -1 after exhausting max_tries -- and a
37// -1 means the caller MUST NOT stitch this fragment (that is exactly how a broken fragment gets avoided).
38func rdl_fetch_retry(url: *u8, urllen: i64, out: *u8, outcap: i64, kind: i64,
39 fetch_fn: func(*u8, i64, i64, *u8, i64, i64) -> i64, rctx: i64,
40 max_tries: i64, backoff_ms: i64) -> i64 {
41 var attempt: i64 = 0
42 while attempt < max_tries {
43 let n: i64 = fetch_fn(url, urllen, attempt, out, outcap, rctx)
44 if n > 0 { if rdl_verify(out, n, kind) == 1 { return n } } // got bytes AND they're whole -> done
45 // network failure OR integrity failure -> exponential backoff, then retry
46 if backoff_ms > 0 { var d: i64 = backoff_ms; var s: i64 = 0; while s < attempt { d = d * 2; s = s + 1 } sys_sleep_ms(d) }
47 attempt = attempt + 1
48 }
49 return 0 - 1
50}
51
52// ---- resume: a done-bitmap persisted so an interrupted run picks up where it stopped ----
53// state is a byte-per-segment array (state[idx]=1 => that segment is already downloaded+verified). On resume
54// the driver skips done segments (no re-download) and only the missing ones are fetched (no holes).
55func rdl_state_mark(state: *u8, idx: i64) -> i64 { state[idx] = 1 as u8; return 0 }
56func rdl_state_done(state: *u8, idx: i64) -> i64 { if (state[idx] & 0xff) == 1 { return 1 } return 0 }
57func rdl_state_count(state: *u8, n: i64) -> i64 { var c: i64 = 0; var i: i64 = 0; while i < n { if (state[i] & 0xff) == 1 { c = c + 1 } i = i + 1 } return c }
58// persist the done-bitmap to `path` (n bytes). Atomic-ish: caller can write to .tmp then rename in prod.
59func rdl_state_save(path: *u8, state: *u8, n: i64) -> i64 {
60 let fd: i64 = sys_openat_wr(path, 0x1a4)
61 if fd < 0 { return 0 - 1 }
62 let w: i64 = sys_write(fd, state, n)
63 sys_close(fd)
64 if w != n { return 0 - 1 }
65 return 0
66}
67// load the done-bitmap from `path` into state (n bytes); returns bytes read, or 0 if absent (fresh download).
68func rdl_state_load(path: *u8, state: *u8, n: i64) -> i64 {
69 let fd: i64 = sys_openat_rd(path)
70 if fd < 0 { var i: i64 = 0; while i < n { state[i] = 0 as u8; i = i + 1 } return 0 }
71 let rd: i64 = sys_read(fd, state, n)
72 sys_close(fd)
73 return rd
74}