code wiki / (root) / nx_torrent_keep.nx

nx_torrent_keep.nx source

↩ module page · 77 lines · 4664 B

1// nx_torrent_keep.nx -- SOVEREIGN local keeper for the /torrent media daemon (:8097). 2// 3// Mirrors the NAS-side nx_hostctl reader-keeper: it ENSURES the daemon is up by delegating to the 4// idempotent nx_torrent_up (so the build/launch logic is NOT duplicated -- DRY #15), then SUPERVISES it -- 5// polling liveness and, on death, respawning with an ESCALATING crash-loop backoff. never-brick #26 / 6// graceful-degradation #14: a persistently-broken daemon backs off to a capped 30s retry, NEVER a tight 7// respawn loop. Runs FOREVER; it is ignited at Windows logon (the user Startup .vbs) and kept resident by 8// the locked-in vmIdleTimeout, so the LOCAL daemon gets the same death-respawn supervision the NAS fleet 9// already has under nx_hostctl. Takes NO args, so the WOMB runs it directly: `nx_sov_build_run.elf 10// nx_torrent_keep` (no --build-only/persisted-elf dance needed). 11// 12// license_tier: ORIGINAL layer: L7 (local supervisor over the L6 daemon) 13// module: nishi-core.torrent.keep 14// depends: nishi-core.syscalls 15import "nx_syscalls.nx" 16 17const KEEP_HEALTHY_MS: i64 = 10000 // a daemon that ran >= this before dying is "healthy" -> reset fails 18const KEEP_POLL_MS: i64 = 5000 // liveness poll cadence 19const KEEP_BACKOFF_STEP_MS: i64 = 2000 // backoff grows by this per consecutive fast death 20const KEEP_BACKOFF_MAX_MS: i64 = 30000 // ...capped here (never a tight loop) 21 22func k_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 23func k_putn(v: i64) -> i64 { 24 let bb: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) } 25 let t: *u8 = sys_mmap(28); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 } 26 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 27 var i: i64 = 0; while i < k { bb[i] = t[k-1-i]; i = i + 1 } 28 sys_write(1, bb, k); return 0 29} 30// read the daemon pid the way nx_torrent_up writes it. -1 if absent/empty. 31func k_read_pid(path: *u8) -> i64 { 32 let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 - 1 } 33 let b: *u8 = sys_mmap(32); let n: i64 = sys_read(fd, b, 31); sys_close(fd) 34 if n <= 0 { return 0 - 1 } 35 var v: i64 = 0; var i: i64 = 0 36 while i < n { let c: i64 = b[i] as i64; if c >= 48 { if c <= 57 { v = v*10 + (c-48); i = i + 1 } else { i = n } } else { i = n } } 37 return v 38} 39// kill(pid,0) probes existence/permission without signalling -> 1 alive, 0 gone. 40func k_alive(pid: i64) -> i64 { if pid <= 0 { return 0 } if nx_kill(pid, 0) == 0 { return 1 } return 0 } 41 42// fork+exec the WOMB in up-mode = idempotent ensure-up (launches the daemon if down, else "already UP"). 43// build/launch noise -> /dev/null. Returns the WOMB child's exit code. Relative womb path resolves against 44// the keeper's cwd (the WOMB runs us with --cd nxc2; the forked child inherits that cwd). 45func k_ensure_up(envp: *i64) -> i64 { 46 let womb: *u8 = "_offc/nx_sov_build_run.elf" as *u8 47 let pid: i64 = sys_fork() 48 if pid == 0 { 49 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4) 50 if dn >= 0 { sys_dup3(dn, 1, 0); sys_dup3(dn, 2, 0) } 51 let av: *i64 = sys_mmap(8*4) as *i64; av[0] = womb as i64; av[1] = "nx_torrent_up" as *u8 as i64; av[2] = 0 52 sys_execve(womb, av, envp); sys_exit(127) 53 } 54 let st: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, st, 0) 55 return (st[0] >> 8) & 0xff 56} 57 58func main() -> i64 { 59 let pidfile: *u8 = "/tmp/nx_torrentd.pid" as *u8 60 let envp: *i64 = sys_mmap(8*4) as *i64; envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0 61 k_puts("[torrent-keep] sovereign keeper: ensure + supervise nx_torrent_daemon (:8097), respawn-on-death\n" as *u8) 62 var fails: i64 = 0 63 while 1 == 1 { 64 k_ensure_up(envp) // (re)launch the daemon if it is not running 65 let pid: i64 = k_read_pid(pidfile) 66 let t0: i64 = sys_now_ms() 67 if k_alive(pid) == 1 { k_puts("[torrent-keep] daemon UP pid=" as *u8); k_putn(pid); k_puts(" -> supervising\n" as *u8) } 68 while k_alive(pid) == 1 { sys_sleep_ms(KEEP_POLL_MS) } // block until the daemon dies 69 let ran: i64 = sys_now_ms() - t0 70 if ran >= KEEP_HEALTHY_MS { fails = 0 } else { fails = fails + 1 } 71 var backoff: i64 = fails * KEEP_BACKOFF_STEP_MS 72 if backoff > KEEP_BACKOFF_MAX_MS { backoff = KEEP_BACKOFF_MAX_MS } 73 k_puts("[torrent-keep] daemon DOWN (ran_ms=" as *u8); k_putn(ran); k_puts(" fails=" as *u8); k_putn(fails); k_puts(") -> respawn in ms=" as *u8); k_putn(backoff); k_puts("\n" as *u8) 74 if backoff > 0 { sys_sleep_ms(backoff) } 75 } 76 return 0 77}