code wiki / (root) / nx_state_spool.nx

nx_state_spool.nx source

↩ module page · 63 lines · 3064 B

1// nx_state_spool.nx -- CLI of the store-and-forward state spool (CR-R1a; NAS=hub, laptop=worker: 2// sync to the NAS whenever reachable, go local when it isn't, drain on reconnect). 3// usage: 4// nx_state_spool spool <spoolfile> <line> append one state line locally (flock'd) 5// nx_state_spool drain <spoolfile> <transport_elf> deliver each line via transport (argv[1]= 6// line, exit 0=delivered); failures KEPT 7// lock = <spoolfile>.lock, tmp = <spoolfile>.tmp (atomic rewrite). Exit 0 on success (kept>0 is 8// NOT an error -- offline is a normal state); 2 = usage; 3 = spool/lock failure. 9// license_tier: ORIGINAL expect_exit: 0 10import "nx_syscalls.nx" 11import "nx_state_spool_core.nx" 12import "nx_itoa_lib.nx" // shared MSB-first emitter; declared explicitly rather than leaned on transitively 13const K_MAGIC_1024: i64 = 1024 14 15func sp_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 16 17// MIGRATED to the shared emitter 2026-08-06 (debt 1785516350). The old body mmapped a 32-byte 18// scratch and never freed it -- at page granularity that is 4096B leaked PER CALL, and this is the 19// exact clone shape nx_itoa_lib's header quotes as the reason ~87 sites hand-rolled their own. 20// nxi_out runs the SAME MSB-first ccz_cat_num digits through a shim that always frees, so the 21// emitted bytes are identical including the sign; only the leak goes away. 22func sp_putn(v: i64) -> i64 { nxi_out(v); return 0 } 23 24func sp_streq(a: *u8, b: *u8) -> i64 { 25 var i: i64 = 0 26 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 27 if b[i] != (0 as u8) { return 0 } 28 return 1 29} 30 31func main(argc: i64, argv: *i64) -> i64 { 32 if argc < 4 { sp_puts("usage: nx_state_spool spool <file> <line> | drain <file> <transport_elf>\n" as *u8); return 2 } 33 let sub: *u8 = argv[1] as *u8 34 let spool: *u8 = argv[2] as *u8 35 let lock: *u8 = sys_mmap(K_MAGIC_1024) 36 var o: i64 = 0 37 o = ccz_cat_str(lock, o, spool) 38 o = ccz_cat_str(lock, o, ".lock" as *u8) 39 if sp_streq(sub, "spool" as *u8) == 1 { 40 let r: i64 = ssp_spool(spool, lock, argv[3] as *u8) 41 if r < 0 { sp_puts("SSP spool-failed\n" as *u8); return 3 } 42 sp_puts("SSP spooled\n" as *u8) 43 return 0 44 } 45 if sp_streq(sub, "drain" as *u8) == 1 { 46 let tmp: *u8 = sys_mmap(K_MAGIC_1024) 47 var t: i64 = 0 48 t = ccz_cat_str(tmp, t, spool) 49 t = ccz_cat_str(tmp, t, ".tmp" as *u8) 50 let sent: *i64 = sys_mmap(16) as *i64 51 let kept: *i64 = sys_mmap(16) as *i64 52 let r: i64 = ssp_drain(spool, lock, tmp, argv[3] as *u8, sent, kept) 53 if r < 0 { sp_puts("SSP drain-failed (lock/tmp)\n" as *u8); return 3 } 54 sp_puts("SSP drain sent=" as *u8) 55 sp_putn(sent[0]) 56 sp_puts(" kept=" as *u8) 57 sp_putn(kept[0]) 58 sp_puts("\n" as *u8) 59 return 0 60 } 61 sp_puts("usage: nx_state_spool spool <file> <line> | drain <file> <transport_elf>\n" as *u8) 62 return 2 63}