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}