code wiki / (root) / nx_torrent_up.nx

nx_torrent_up.nx source

↩ module page · 156 lines · 9669 B

1// nx_torrent_up.nx -- SOVEREIGN bring-up + lifecycle for the /torrent UI stack (X-TORRENT-UI-002). 2// REPLACES the (forbidden) bash bring-up entirely. Pure NishiLang orchestration -- sys_fork / execve / 3// wait4 / kill + openat/read/write. NO bash, NO sh, NO pkill/curl/nohup/timeout. It builds the three 4// organs through the WOMB in --build-only mode (so a worker's live-download side effect never fires), 5// then launches the daemon detached and records its pid so it can be stopped sovereignly. 6// 7// nx_torrent_up -> build-if-missing (worker, discover, daemon) then launch daemon (idempotent) 8// nx_torrent_up down -> kill the daemon by pidfile + signal any worker to self-stop 9// nx_torrent_up status -> report whether the daemon process is alive 10// 11// Run it the sovereign way: ./_offc/nx_sov_build_run.elf nx_torrent_up (WOMB builds + runs this = bring-up) 12// license_tier: ORIGINAL layer: L7 (supervises the L6 daemon over the L4/L5 organs) 13// module: nishi-core.torrent.up 14// depends: nishi-core.syscalls 15import "nx_syscalls.nx" 16 17func tu_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 18func tu_putn(v: i64) -> i64 { 19 let bb: *u8 = sys_mmap(28); var m: i64 = v 20 if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) } 21 let t: *u8 = sys_mmap(28); var k: i64 = 0 22 if m == 0 { t[0] = 48 as u8; k = 1 } 23 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 24 var i: i64 = 0; while i < k { bb[i] = t[k-1-i]; i = i + 1 } 25 sys_write(1, bb, k); return 0 26} 27func tu_streq(a: *u8, b: *u8) -> i64 { 28 var i: i64 = 0 29 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 30 if b[i] != (0 as u8) { return 0 } 31 return 1 32} 33func tu_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 } 34// mtime (seconds) of a file via fstatat (st_mtime @ off 88 of the x86_64 struct stat). -1 if missing. 35func tu_mtime(path: *u8) -> i64 { 36 let stbuf: *u8 = sys_mmap(160) 37 if sys_fstatat(path, stbuf) == 0 { let mp: *i64 = (((stbuf as i64) + 88)) as *i64; return mp[0] } 38 return 0 - 1 39} 40// rebuild needed? YES if the built elf is missing, or the SOURCE .nx is newer than it. If the source 41// isn't visible (mtime<0) keep the existing elf (don't force). This is what lets a plain, arg-free 42// `nx_torrent_up` pick up source edits and redeploy them (the WOMB drops args, so `up` must self-detect). 43func tu_need_build(src: *u8, elf: *u8) -> i64 { 44 if tu_exists(elf) == 0 { return 1 } 45 let ms: i64 = tu_mtime(src); let me: i64 = tu_mtime(elf) 46 if ms < 0 { return 0 } 47 if ms > me { return 1 } 48 return 0 49} 50 51func tu_write_pid(path: *u8, pid: i64) -> i64 { 52 let fd: i64 = sys_openat_wr(path, 0x1a4) 53 if fd < 0 { return 0 - 1 } 54 let b: *u8 = sys_mmap(32); var m: i64 = pid; var k: i64 = 0 55 if m == 0 { b[0] = 48 as u8; k = 1 } else { 56 let t: *u8 = sys_mmap(32); var j: i64 = 0 57 while m > 0 { t[j] = (48 + (m % 10)) as u8; m = m / 10; j = j + 1 } 58 while j > 0 { b[k] = t[j-1]; k = k + 1; j = j - 1 } 59 } 60 sys_write(fd, b, k); sys_close(fd); return 0 61} 62func tu_read_pid(path: *u8) -> i64 { 63 let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 - 1 } 64 let b: *u8 = sys_mmap(32); let n: i64 = sys_read(fd, b, 31); sys_close(fd) 65 if n <= 0 { return 0 - 1 } 66 var v: i64 = 0; var i: i64 = 0 67 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 } } 68 return v 69} 70 71// fork + execve the WOMB in --build-only mode (no run); parent waits. Returns child exit code. 72func tu_build(womb: *u8, name: *u8, envp: *i64) -> i64 { 73 let pid: i64 = sys_fork() 74 if pid == 0 { 75 let av: *i64 = sys_mmap(8*5) as *i64 76 av[0] = womb as i64; av[1] = name as i64; av[2] = "--build-only" as *u8 as i64; av[3] = 0 77 sys_execve(womb, av, envp); sys_exit(127) 78 } 79 let st: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, st, 0) 80 return (st[0] >> 8) & 0xff 81} 82 83func main(argc: i64, argv: *i64) -> i64 { 84 let womb: *u8 = "_offc/nx_sov_build_run.elf" as *u8 85 let pidfile: *u8 = "/tmp/nx_torrentd.pid" as *u8 86 let delf: *u8 = "/tmp/nx_torrent_daemon.sov.elf" as *u8 87 let getf: *u8 = "/tmp/nx_torrent_get.sov.elf" as *u8 88 let discf: *u8 = "/tmp/nx_magnet_discover.sov.elf" as *u8 89 let hlsf: *u8 = "/tmp/nx_hls_get.sov.elf" as *u8 90 let galxf: *u8 = "/tmp/nx_galx_vidindex.sov.elf" as *u8 91 let vidf: *u8 = "/tmp/nx_video_get.sov.elf" as *u8 92 let tsmp4f: *u8 = "/tmp/nx_ts2mp4.sov.elf" as *u8 93 let fmp4f: *u8 = "/tmp/nx_ts2fmp4.sov.elf" as *u8 94 let delsrc: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/runtime/nx_torrent_daemon.nx" as *u8 95 let getsrc: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/runtime/nx_torrent_get.nx" as *u8 96 let discsrc: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/runtime/nx_magnet_discover.nx" as *u8 97 let hlssrc: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/runtime/nx_hls_get.nx" as *u8 98 let galxsrc: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/runtime/nx_galx_vidindex.nx" as *u8 99 let vidsrc: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/runtime/nx_video_get.nx" as *u8 100 let tsmp4src: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/runtime/nx_ts2mp4.nx" as *u8 101 let fmp4src: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/runtime/nx_ts2fmp4.nx" as *u8 102 let ctl: *u8 = "/mnt/c/Users/elder/Downloads/nishi-torrents/download.control" as *u8 103 let envp: *i64 = sys_mmap(8*4) as *i64; envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0 104 105 var mode: *u8 = "up" as *u8 106 if argc >= 2 { mode = argv[1] as *u8 } 107 108 if tu_streq(mode, "down" as *u8) == 1 { 109 let pid: i64 = tu_read_pid(pidfile) 110 if pid > 0 { nx_kill(pid, 9) } 111 let cf: i64 = sys_openat_wr(ctl, 0x1a4); if cf >= 0 { sys_write(cf, "removed" as *u8, 7); sys_close(cf) } 112 tu_puts("[torrent-up] DOWN (daemon pid=" as *u8); tu_putn(pid); tu_puts(" signalled; worker told to stop)\n" as *u8) 113 sys_exit(0); return 0 114 } 115 if tu_streq(mode, "status" as *u8) == 1 { 116 let pid: i64 = tu_read_pid(pidfile) 117 if pid > 0 { if nx_kill(pid, 0) == 0 { tu_puts("[torrent-up] UP pid=" as *u8); tu_putn(pid); tu_puts(" -> http://localhost:8097/torrent\n" as *u8); sys_exit(0); return 0 } } 118 tu_puts("[torrent-up] DOWN\n" as *u8); sys_exit(1); return 1 119 } 120 121 // ---- up (default): (re)build any organ whose SOURCE .nx is newer than its built elf (or missing), 122 // then launch the daemon detached. The mtime check makes a plain `nx_torrent_up` DEPLOY source edits 123 // (the WOMB drops args, so this arg-free path must self-detect changes) -- no manual rm, no shell. ---- 124 if tu_need_build(getsrc, getf) == 1 { tu_puts("[torrent-up] building worker (nx_torrent_get)...\n" as *u8); tu_build(womb, "nx_torrent_get" as *u8, envp) } 125 if tu_need_build(discsrc, discf) == 1 { tu_puts("[torrent-up] building discover (nx_magnet_discover)...\n" as *u8); tu_build(womb, "nx_magnet_discover" as *u8, envp) } 126 if tu_need_build(hlssrc, hlsf) == 1 { tu_puts("[torrent-up] building HLS downloader (nx_hls_get)...\n" as *u8); tu_build(womb, "nx_hls_get" as *u8, envp) } 127 if tu_need_build(galxsrc, galxf) == 1 { tu_puts("[torrent-up] building gallery indexer (nx_galx_vidindex)...\n" as *u8); tu_build(womb, "nx_galx_vidindex" as *u8, envp) } 128 if tu_need_build(vidsrc, vidf) == 1 { tu_puts("[torrent-up] building video downloader (nx_video_get)...\n" as *u8); tu_build(womb, "nx_video_get" as *u8, envp) } 129 if tu_need_build(tsmp4src, tsmp4f) == 1 { tu_puts("[torrent-up] building TS->MP4 remuxer (nx_ts2mp4)...\n" as *u8); tu_build(womb, "nx_ts2mp4" as *u8, envp) } 130 if tu_need_build(fmp4src, fmp4f) == 1 { tu_puts("[torrent-up] building TS->fMP4 streamer (nx_ts2fmp4)...\n" as *u8); tu_build(womb, "nx_ts2fmp4" as *u8, envp) } 131 var daemon_rebuilt: i64 = 0 132 if tu_need_build(delsrc, delf) == 1 { tu_puts("[torrent-up] building daemon (nx_torrent_daemon)...\n" as *u8); tu_build(womb, "nx_torrent_daemon" as *u8, envp); daemon_rebuilt = 1 } 133 134 // idempotent: if a recorded daemon is still alive AND we did NOT just rebuild it, don't double-launch 135 // (a 2nd bind would fail). If we DID rebuild the daemon, kill the stale one so the fresh build binds :8097. 136 let old: i64 = tu_read_pid(pidfile) 137 if old > 0 { if nx_kill(old, 0) == 0 { 138 if daemon_rebuilt == 0 { tu_puts("[torrent-up] already UP pid=" as *u8); tu_putn(old); tu_puts(" -> http://localhost:8097/torrent\n" as *u8); sys_exit(0); return 0 } 139 nx_kill(old, 9); sys_sleep_ms(500); tu_puts("[torrent-up] daemon rebuilt -> restarting (killed stale pid=" as *u8); tu_putn(old); tu_puts(")\n" as *u8) 140 } } 141 142 // launch the daemon detached: child redirects stdio to /dev/null + execs the daemon; parent records 143 // the pid and exits, so the daemon reparents to init and outlives this bring-up (sovereign nohup). 144 let pid: i64 = sys_fork() 145 if pid == 0 { 146 nx_setsid() // NEW session: SIGHUP-immune so the daemon survives this bring-up command's exit 147 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4) 148 if dn >= 0 { sys_dup3(dn, 0, 0); sys_dup3(dn, 1, 0); sys_dup3(dn, 2, 0) } 149 let av: *i64 = sys_mmap(8*4) as *i64; av[0] = delf as i64; av[1] = 0 150 sys_execve(delf, av, envp); sys_exit(127) 151 } 152 tu_write_pid(pidfile, pid) 153 sys_sleep_ms(700) 154 tu_puts("[torrent-up] UP pid=" as *u8); tu_putn(pid); tu_puts(" -> http://localhost:8097/torrent\n" as *u8) 155 sys_exit(0); return 0 156}