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}