nx_galx_saveimg.nx source
↩ module page · 118 lines · 5042 B
1// nx_galx_saveimg.nx -- ingest ONE media file into the gallery so it SHOWS in the grid and SERVES
2// live with NO restart. The reusable "save to gallery" primitive behind 4chan-save and the safe-browse
3// adapters: a source downloads bytes to a dir, this makes them a first-class gallery image.
4//
5// Composes the sovereign cid + BOTH gallery indexes the 2026-08-07 native-store work exposed:
6// 1. cid = "nxc1-" + sha256hex(content) -- 69 chars, the gallery cid canon (matches nxc1-* gens).
7// 2. copy the file to <savedir>/<cid> -- the resolver's target path.
8// 3. APPEND "<cid>\t<savedpath>\n" to <cidtsv> (knowledge/status/galx_cid_paths.tsv). gs_sidecar's
9// FAST path is the boot-loaded O(1) index; on a MISS it reads THIS tsv FRESH per request, so a new
10// cid resolves LIVE with no restart, and the boot rebuild-preserving later merges it durably.
11// 4. nx_galx_view_prepend(<viewindex>, cid) -- 70-byte records NEWEST-FIRST, so the grid LISTS it.
12// Content-addressed: re-saving identical bytes yields the same cid -> idempotent (view PRESENT, tsv dup
13// harmless -- gs_sidecar returns the first match). The vault (nx_mvault_walk <dir> real <source>) owns
14// the durable CID/source record for migration; this organ makes it VISIBLE now.
15//
16// Usage: nx_galx_saveimg <srcfile> <savedir> <viewindex> <cidtsv> [source]
17// -> {"cid":"nxc1-..","bytes":N,"saved":"<savedir>/<cid>","view_added":0|1} exit 0 ok / 1 err
18// license_tier: ORIGINAL
19
20import "nx_syscalls.nx"
21import "nx_sha256.nx"
22import "nx_galx_viewadd_lib.nx"
23const SI_MAGIC_1024: i64 = 1024
24const SI_MAGIC_1152: i64 = 1152
25
26const SI_IMG_CAP: i64 = 33554432
27
28func si_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return sys_write(1, s, n) }
29func si_apps(dst: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { dst[o+i] = s[i]; i = i + 1 } return o + i }
30func si_num(dst: *u8, o: i64, v: i64) -> i64 {
31 if v == 0 { dst[o] = 48 as u8; return o + 1 }
32 let t: *u8 = sys_mmap(32); var m: i64 = v; var k: i64 = 0
33 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
34 var i: i64 = 0; while i < k { dst[o+i] = t[k-1-i]; i = i + 1 } return o + k
35}
36
37// 32-byte digest -> 64 lowercase hex chars at out[0..64]
38func si_hex(dig: *u8, out: *u8) -> i64 {
39 let hx: *u8 = "0123456789abcdef" as *u8
40 var i: i64 = 0
41 while i < 32 {
42 let b: i64 = dig[i] as i64
43 out[i*2] = hx[(b >> 4) & 15]
44 out[i*2+1] = hx[b & 15]
45 i = i + 1
46 }
47 return 64
48}
49
50func main(argc: i64, argv: *i64) -> i64 {
51 if argc < 5 {
52 si_puts("usage: nx_galx_saveimg <srcfile> <savedir> <viewindex> <cidtsv> [source]\n" as *u8)
53 return 2
54 }
55 let src: *u8 = argv[1] as *u8
56 let savedir: *u8 = argv[2] as *u8
57 let viewidx: *u8 = argv[3] as *u8
58 let cidtsv: *u8 = argv[4] as *u8
59
60 let sp: *i64 = sys_mmap(16) as *i64
61 let buf: *u8 = sys_read_file(src, sp)
62 if (buf as i64) == 0 { si_puts("{\"error\":\"cannot read src\"}\n" as *u8); return 1 }
63 let n: i64 = sp[0]
64 if n <= 0 { si_puts("{\"error\":\"empty src\"}\n" as *u8); return 1 }
65
66 let dig: *u8 = sys_mmap(64)
67 sha256_digest(buf, n, dig)
68 let cid: *u8 = sys_mmap(96)
69 var co: i64 = si_apps(cid, 0, "nxc1-" as *u8)
70 let hx: *u8 = sys_mmap(96)
71 si_hex(dig, hx)
72 var h: i64 = 0
73 while h < 64 { cid[co] = hx[h]; co = co + 1; h = h + 1 }
74 cid[co] = 0 as u8
75
76 let dest: *u8 = sys_mmap(SI_MAGIC_1024)
77 var do2: i64 = si_apps(dest, 0, savedir)
78 dest[do2] = 47 as u8; do2 = do2 + 1
79 var c2: i64 = 0
80 while c2 < 69 { dest[do2] = cid[c2]; do2 = do2 + 1; c2 = c2 + 1 }
81 dest[do2] = 0 as u8
82
83 __syscall(258, 0 - 100, savedir as i64, 0x1ed, 0, 0, 0)
84
85 let fdo: i64 = sys_openat_wr(dest, 0x1a4)
86 if fdo < 0 { si_puts("{\"error\":\"cannot open dest\"}\n" as *u8); return 1 }
87 if sys_write(fdo, buf, n) != n { sys_close(fdo); si_puts("{\"error\":\"short write\"}\n" as *u8); return 1 }
88 sys_close(fdo)
89
90 let row: *u8 = sys_mmap(SI_MAGIC_1152)
91 var ro: i64 = 0
92 var c3: i64 = 0
93 while c3 < 69 { row[ro] = cid[c3]; ro = ro + 1; c3 = c3 + 1 }
94 row[ro] = 9 as u8; ro = ro + 1
95 ro = si_apps(row, ro, dest)
96 row[ro] = 10 as u8; ro = ro + 1
97 let fdt: i64 = sys_openat_rdwr(cidtsv, 0x1a4)
98 if fdt >= 0 {
99 sys_lseek(fdt, 0, 2)
100 sys_write(fdt, row, ro)
101 sys_close(fdt)
102 }
103
104 let va: i64 = nx_galx_view_prepend(viewidx, cid)
105 var added: i64 = 0
106 if va == NXV_ADDED { added = 1 }
107
108 let out: *u8 = sys_mmap(SI_MAGIC_1152)
109 var oo: i64 = si_apps(out, 0, "{\"cid\":\"" as *u8)
110 var c4: i64 = 0
111 while c4 < 69 { out[oo] = cid[c4]; oo = oo + 1; c4 = c4 + 1 }
112 oo = si_apps(out, oo, "\",\"bytes\":" as *u8); oo = si_num(out, oo, n)
113 oo = si_apps(out, oo, ",\"saved\":\"" as *u8); oo = si_apps(out, oo, dest)
114 oo = si_apps(out, oo, "\",\"view_added\":" as *u8); oo = si_num(out, oo, added)
115 oo = si_apps(out, oo, "}\n" as *u8)
116 sys_write(1, out, oo)
117 return 0
118}