code wiki / (root) / nx_swarm_lib.nx

nx_swarm_lib.nx source

↩ module page · 172 lines · 5816 B

1// nx_swarm_lib.nx -- SWARM FABRIC shared lib: the NODE-row contract (validate/freshness), bounded 2// reads, and the CLI path law. Single source of truth for the fabric wire format -- consumed by 3// nx_swarm_beat (store) + nx_swarm_place (placement brain). Extracted 2026-07-15 (SF-R2). 4// Row contract (v2 positional, emitted by nx_node_beacon): 5// NODE <name> <cpu> <load> <ncpu> <lpc> <memu> <mema> <memt> <conns> <ts_us> <temp_mc> <batt_pct> 6// license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_framed_append.nx" 9const K_MAGIC_60000000: i64 = 60000000 10const K_MAGIC_1000000: i64 = 1000000 11 12// CLI path guard: must end ".log" or ".snap"; no ".."; bare basename (no '/') OR under /tmp/. 13func sb_path_ok(p: *u8) -> i64 { 14 let n: i64 = fa_len(p) 15 if n < 5 { return 0 } 16 // no ".." anywhere 17 var i: i64 = 0 18 while i + 1 < n { 19 if (p[i] as i64) == 46 { if (p[i + 1] as i64) == 46 { return 0 } } 20 i = i + 1 21 } 22 // extension .log or .snap 23 var ext_ok: i64 = 0 24 if n >= 4 { 25 if (p[n-4] as i64) == 46 { if (p[n-3] as i64) == 108 { if (p[n-2] as i64) == 111 { if (p[n-1] as i64) == 103 { ext_ok = 1 } } } } 26 } 27 if n >= 5 { 28 if (p[n-5] as i64) == 46 { if (p[n-4] as i64) == 115 { if (p[n-3] as i64) == 110 { if (p[n-2] as i64) == 97 { if (p[n-1] as i64) == 112 { ext_ok = 1 } } } } } 29 } 30 if ext_ok == 0 { return 0 } 31 // bare basename (no '/') is fine 32 var has_slash: i64 = 0 33 i = 0 34 while i < n { if (p[i] as i64) == 47 { has_slash = 1 } i = i + 1 } 35 if has_slash == 0 { return 1 } 36 // otherwise must start "/tmp/" 37 if n < 6 { return 0 } 38 if (p[0] as i64) != 47 { return 0 } 39 if (p[1] as i64) != 116 { return 0 } 40 if (p[2] as i64) != 109 { return 0 } 41 if (p[3] as i64) != 112 { return 0 } 42 if (p[4] as i64) != 47 { return 0 } 43 return 1 44} 45 46// bounded whole-file read; bytes read or -1 on open fail 47func sb_read(path: *u8, buf: *u8, cap: i64) -> i64 { 48 let fd: i64 = sys_openat_rd(path) 49 if fd < 0 { return 0 - 1 } 50 var tot: i64 = 0 51 var go: i64 = 1 52 while go == 1 { 53 if tot >= cap { go = 0 } else { 54 let r: i64 = sys_read(fd, (buf as i64 + tot) as *u8, cap - tot) 55 if r <= 0 { go = 0 } else { tot = tot + r } 56 } 57 } 58 sys_close(fd) 59 return tot 60} 61 62// substring present? (n = haystack len) 63func sb_has(buf: *u8, n: i64, needle: *u8) -> i64 { 64 let m: i64 = fa_len(needle) 65 if m == 0 { return 0 } 66 var i: i64 = 0 67 while i + m <= n { 68 var k: i64 = 0 69 var hit: i64 = 1 70 while k < m { if buf[i + k] != needle[k] { hit = 0; k = m } else { k = k + 1 } } 71 if hit == 1 { return 1 } 72 i = i + 1 73 } 74 return 0 75} 76 77// signed decimal at p (within [p,n)); 1 ok / 0 no-digits; value -> vout[0], end -> pend[0] 78func sb_pint(buf: *u8, n: i64, p: i64, vout: *i64, pend: *i64) -> i64 { 79 var i: i64 = p 80 var neg: i64 = 0 81 if i < n { if (buf[i] as i64) == 45 { neg = 1; i = i + 1 } } 82 var v: i64 = 0 83 var d: i64 = 0 84 var go: i64 = 1 85 while go == 1 { 86 if i >= n { go = 0 } else { 87 let c: i64 = buf[i] as i64 88 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); d = d + 1; i = i + 1 } else { go = 0 } } else { go = 0 } 89 } 90 } 91 if d == 0 { return 0 } 92 if neg == 1 { v = 0 - v } 93 vout[0] = v 94 pend[0] = i 95 return 1 96} 97 98// validate one NODE row of exactly 13 tokens; name span -> nso/nlo, ts (token 10) -> tso. 1 ok / 0 bad. 99func sb_validate(row: *u8, n: i64, nso: *i64, nlo: *i64, tso: *i64) -> i64 { 100 if n < 6 { return 0 } 101 if row[0] != (78 as u8) { return 0 } 102 if row[1] != (79 as u8) { return 0 } 103 if row[2] != (68 as u8) { return 0 } 104 if row[3] != (69 as u8) { return 0 } 105 if row[4] != (32 as u8) { return 0 } 106 var i: i64 = 5 107 let ns: i64 = i 108 var go: i64 = 1 109 while go == 1 { 110 if i >= n { go = 0 } else { 111 if (row[i] as i64) == 32 { go = 0 } else { 112 if (row[i] as i64) == 10 { return 0 } 113 i = i + 1 114 } 115 } 116 } 117 let nl: i64 = i - ns 118 if nl < 1 { return 0 } 119 if nl > 32 { return 0 } 120 let vout: *i64 = sys_mmap(16) as *i64 121 let pend: *i64 = sys_mmap(16) as *i64 122 var t: i64 = 2 123 var ts: i64 = 0 - 1 124 while t <= 12 { 125 if i >= n { return 0 } 126 if (row[i] as i64) != 32 { return 0 } 127 i = i + 1 128 let ok: i64 = sb_pint(row, n, i, vout, pend) 129 if ok == 0 { return 0 } 130 if t == 10 { ts = vout[0] } 131 i = pend[0] 132 t = t + 1 133 } 134 // after the last token: only end / newline allowed (strict 13-token contract) 135 if i < n { 136 if (row[i] as i64) != 10 { return 0 } 137 if i + 1 < n { return 0 } 138 } 139 nso[0] = ns 140 nlo[0] = nl 141 tso[0] = ts 142 return 1 143} 144 145// parse ALL 11 numeric fields of a validated row into f[0..10] = cpu,load,ncpu,lpc,memu,mema,memt,conns,ts,temp,batt. 146// returns 1 ok / 0 bad (same strictness as sb_validate). 147func sb_fields(row: *u8, n: i64, f: *i64) -> i64 { 148 let nso: *i64 = sys_mmap(16) as *i64 149 let nlo: *i64 = sys_mmap(16) as *i64 150 let tso: *i64 = sys_mmap(16) as *i64 151 if sb_validate(row, n, nso, nlo, tso) == 0 { return 0 } 152 let vout: *i64 = sys_mmap(16) as *i64 153 let pend: *i64 = sys_mmap(16) as *i64 154 var i: i64 = nso[0] + nlo[0] 155 var t: i64 = 0 156 while t < 11 { 157 i = i + 1 158 sb_pint(row, n, i, vout, pend) 159 f[t] = vout[0] 160 i = pend[0] 161 t = t + 1 162 } 163 return 1 164} 165 166// pure freshness verdict: 1 FRESH / 0 STALE. Future-forged ts (beyond 60s skew) is STALE too. 167func sb_fresh(ts: i64, now: i64, window_sec: i64) -> i64 { 168 if ts <= 0 { return 0 } 169 if ts > now + K_MAGIC_60000000 { return 0 } 170 if now - ts < window_sec * K_MAGIC_1000000 { return 1 } 171 return 0 172}