code wiki / (root) / nx_media_env.nx

nx_media_env.nx source

↩ module page · 109 lines · 6385 B

1// nx_media_env.nx -- SOVEREIGN, PORTABLE launch config for the media/torrent daemon. 2// 3// The per-spoke storage layout is DATA-DRIVEN (CLAUDE.md #11/#17): it lives in a profile TABLE here, NOT 4// hardcoded in the daemon and NOT in a .tsv. Porting the daemon to a new spoke (the NAS hub, another box) 5// = ADD A PROFILE ROW -- nothing in the daemon changes. The profile is chosen by name (argv[1], default 6// "dev"); this launcher ensures the area dirs exist, DEPLOYS the bundle's worker elfs into /tmp (the 7// daemon's launch contract: it execs /tmp/nx_*.sov.elf), then execs the daemon with the profile's roots. 8// The SAME bundle therefore runs on the dev laptop and the NAS hub by configuration alone. 9// 10// Used by: the NAS nx_hostctl spawn cmd -> `nx_media_env hub`; the dev box can use `nx_media_env dev`. 11// license_tier: ORIGINAL layer: L7 (portable launch config over the L6 daemon) 12// module: nishi-core.media.env 13// depends: nishi-core.syscalls 14import "nx_syscalls.nx" 15const K_MAGIC_262144: i64 = 262144 16const K_MAGIC_1024: i64 = 1024 17const K_MAGIC_8097: i64 = 8097 18 19func me_streq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } if b[i] != (0 as u8) { return 0 } return 1 } 20func me_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 21 22// join dir + "/" + name -> out (NUL-terminated) 23func me_join(dir: *u8, name: *u8, out: *u8) -> *u8 { 24 var o: i64 = 0; var i: i64 = 0 25 while dir[i] != (0 as u8) { out[o] = dir[i]; o = o + 1; i = i + 1 } 26 out[o] = 47 as u8; o = o + 1 27 i = 0; while name[i] != (0 as u8) { out[o] = name[i]; o = o + 1; i = i + 1 } 28 out[o] = 0 as u8; return out 29} 30 31// chunked copy src -> dst, mode 0777 (executable). Returns 0 on a clean read-to-EOF. Chunked (NOT 32// sys_read_file, which reserves 4 GiB/call -- the F-class leak), so it is safe even for multi-MB elfs. 33func me_copy(src: *u8, dst: *u8) -> i64 { 34 let sf: i64 = sys_openat_rd(src); if sf < 0 { return 0 - 1 } 35 let df: i64 = sys_openat_wr(dst, 0x1ff); if df < 0 { sys_close(sf); return 0 - 1 } 36 let buf: *u8 = sys_mmap(K_MAGIC_262144); var go: i64 = 1 37 while go == 1 { let r: i64 = sys_read(sf, buf, K_MAGIC_262144); if r <= 0 { go = 0 } else { sys_write(df, buf, r) } } 38 sys_close(sf); sys_close(df); return 0 39} 40 41// deploy the bundle's spawn elfs into /tmp (the daemon execs /tmp/nx_*.sov.elf at runtime). Skipped when the 42// bundle already lives in /tmp (the dev box: the WOMB builds straight there). Fixed list = the daemon's 43// spawn targets; add here if the daemon gains a new one. 44func me_deploy_bundle(bundle_dir: *u8) -> i64 { 45 if me_streq(bundle_dir, "/tmp" as *u8) == 1 { return 0 } 46 let names: *i64 = sys_mmap(8*16) as *i64 47 names[0] = "nx_torrent_daemon.sov.elf" as *u8 as i64 48 names[1] = "nx_torrent_get.sov.elf" as *u8 as i64 49 names[2] = "nx_magnet_discover.sov.elf" as *u8 as i64 50 names[3] = "nx_hls_get.sov.elf" as *u8 as i64 51 names[4] = "nx_video_get.sov.elf" as *u8 as i64 52 names[5] = "nx_galx_vidindex.sov.elf" as *u8 as i64 53 names[6] = "nx_ts2fmp4.sov.elf" as *u8 as i64 54 names[7] = "nx_ts2mp4.sov.elf" as *u8 as i64 55 names[8] = 0 56 var i: i64 = 0 57 while names[i] != 0 { 58 let s: *u8 = me_join(bundle_dir, names[i] as *u8, sys_mmap(K_MAGIC_1024)) 59 let d: *u8 = me_join("/tmp" as *u8, names[i] as *u8, sys_mmap(K_MAGIC_1024)) 60 me_copy(s, d) 61 i = i + 1 62 } 63 return 0 64} 65 66// ensure dirs + deploy the bundle + exec the daemon foreground (so the NAS nx_hostctl / dev supervisor 67// tracks the daemon process directly). argv passed to the daemon: media root, owner root, UI shell path. 68func me_launch(sfw: *u8, nsfw: *u8, index: *u8, bundle: *u8, bind_mode: *u8) -> i64 { 69 sys_mkdir(sfw, 0x1ff); sys_mkdir(nsfw, 0x1ff) 70 me_puts("[media-env] launch daemon media=" as *u8); me_puts(sfw); me_puts(" owner=" as *u8); me_puts(nsfw); me_puts("\n" as *u8) 71 // Run the daemon IN-PLACE from the bundle dir. On the NAS hub /tmp is mounted NOEXEC, so the old 72 // copy-to-/tmp-then-exec contract failed; here the daemon execs from /volume1/ai/torrent (exec-friendly) 73 // and finds its worker/ts2fmp4 SIBLINGS via self-dir (/proc/self/cmdline argv[0]) -- no /tmp copy needed. 74 let delf: *u8 = me_join(bundle, "nx_torrent_daemon.sov.elf" as *u8, sys_mmap(K_MAGIC_1024)) 75 let av: *i64 = sys_mmap(8*8) as *i64 76 av[0] = delf as i64; av[1] = sfw as i64; av[2] = nsfw as i64; av[3] = index as i64; av[4] = bind_mode as i64; av[5] = 0 77 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0 78 me_puts("[media-env] exec " as *u8); me_puts(delf); me_puts("\n" as *u8) 79 sys_execve(delf, av, envp); sys_exit(127) 80 return 0 81} 82 83func main(argc: i64, argv: *i64) -> i64 { 84 var profile: *u8 = "dev" as *u8 85 if argc > 1 { profile = argv[1] as *u8 } 86 me_puts("[media-env] profile=" as *u8); me_puts(profile); me_puts("\n" as *u8) 87 88 // ====================== DATA-DRIVEN PROFILE TABLE -- port = add a block ====================== 89 if me_streq(profile, "dev" as *u8) == 1 { 90 // dev laptop: downloads under the Windows Downloads dir; the WOMB builds the bundle straight to /tmp. 91 me_launch("/mnt/c/Users/elder/Downloads/nishi-media" as *u8, 92 "/mnt/c/Users/elder/Downloads/nishi-torrents" as *u8, 93 "/mnt/c/Users/elder/nishi-core/nxc2/sites/nishifamily/torrent/index.html" as *u8, 94 "/tmp" as *u8, "any" as *u8) // dev: 0.0.0.0 for WSL2 localhost-forwarding (browser at http://localhost:K_MAGIC_8097) 95 return 0 96 } 97 if me_streq(profile, "hub" as *u8) == 1 { 98 // NAS hub: self-contained area under /volume1/ai/torrent; the bundle is deployed alongside the daemon. 99 me_launch("/volume1/ai/torrent/media" as *u8, 100 "/volume1/ai/torrent/gallery" as *u8, 101 "/volume1/ai/torrent/index.html" as *u8, 102 "/volume1/ai/torrent" as *u8, "loopback" as *u8) // hub: gateway-only loopback bind (no LAN X-Nishi-Level forge) 103 return 0 104 } 105 // ============================================================================================ 106 107 me_puts("[media-env] UNKNOWN profile (known: dev | hub) -- add a profile block to the table\n" as *u8) 108 sys_exit(2); return 2 109}