code wiki / _hdl_build / nx_galx_tags.nx
nx_galx_tags.nx source
↩ module page · 321 lines · 14969 B
1// nx_galx_tags.nx -- sovereign tag store for the gallery (media-manager migration: tags were missing).
2// Tags live in an append-only log knowledge/status/galx_tags.log, one op per line:
3// <id>\t<tag>\t<v>\n (v=1 add, v=0 remove) -- LAST-WINS per (id,tag), mirrors galx_hidden.log.
4// Reading replays the log to the CURRENT tag set. Append-only = rule-13 additive (history preserved). no main.
5// Tags are assumed pre-sanitised by the POST handler (alnum + space/dash, no quotes/tabs/newlines), so the
6// JSON emitters don't escape. license_tier: ORIGINAL
7import "nx_syscalls.nx"
8const K_MAGIC_16384: i64 = 16384
9const K_MAGIC_65536: i64 = 65536
10const K_MAGIC_4096: i64 = 4096
11const K_MAGIC_1048576: i64 = 1048576
12const K_MAGIC_2097152: i64 = 2097152
13
14// parse the unsigned int in buf[s..e); 0 if none.
15func tg_pint(buf: *u8, s: i64, e: i64) -> i64 {
16 var v: i64 = 0; var p: i64 = s
17 while p < e { let c: i64 = buf[p] as i64; if c < 48 { p = e } else { if c > 57 { p = e } else { v = v*10+(c-48); p = p+1 } } }
18 return v
19}
20// byte-range equality.
21func tg_eqn(a: *u8, ao: i64, alen: i64, b: *u8, bo: i64, blen: i64) -> i64 {
22 if alen != blen { return 0 }
23 var i: i64 = 0
24 while i < alen { if a[ao+i] != b[bo+i] { return 0 } i = i + 1 }
25 return 1
26}
27func tg_emit_u(out: *u8, o: i64, v: i64) -> i64 {
28 if v == 0 { out[o] = 48 as u8; return o + 1 }
29 let t: *u8 = sys_mmap(28); var m: i64 = v; var k: i64 = 0
30 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
31 var j: i64 = k; var oo: i64 = o
32 while j > 0 { j = j - 1; out[oo] = t[j]; oo = oo + 1 }
33 return oo
34}
35// locate the two tabs of a log line [ls..le); writes them to t1p/t2p (-1 if absent). returns 1 if both found.
36func tg_tabs(log: *u8, ls: i64, le: i64, t1p: *i64, t2p: *i64) -> i64 {
37 var t1: i64 = 0 - 1; var t2: i64 = 0 - 1; var p: i64 = ls
38 while p < le { if log[p]==(9 as u8) { if t1 < 0 { t1 = p } else { if t2 < 0 { t2 = p } } } p = p + 1 }
39 t1p[0] = t1; t2p[0] = t2
40 if t1 >= 0 { if t2 >= 0 { return 1 } }
41 return 0
42}
43// emit JSON ["tag",...] of the CURRENT tags for `id` (last-wins, v=1). returns bytes written.
44func tg_tags_for_id(log: *u8, sz: i64, id: i64, out: *u8) -> i64 {
45 let tbuf: *u8 = sys_mmap(K_MAGIC_16384)
46 let toff: *i64 = sys_mmap(8*512) as *i64
47 let tlen: *i64 = sys_mmap(8*512) as *i64
48 let tvv: *i64 = sys_mmap(8*512) as *i64
49 let t1p: *i64 = sys_mmap(16) as *i64
50 let t2p: *i64 = sys_mmap(16) as *i64
51 var nt: i64 = 0; var tb: i64 = 0
52 var i: i64 = 0; var ls: i64 = 0
53 while i <= sz {
54 var nl: i64 = 0; if i == sz { nl = 1 } else { if log[i]==(10 as u8) { nl = 1 } }
55 if nl == 1 {
56 if i > ls { if tg_tabs(log, ls, i, t1p, t2p) == 1 {
57 let t1: i64 = t1p[0]; let t2: i64 = t2p[0]
58 let lid: i64 = tg_pint(log, ls, t1)
59 if lid == id {
60 let ts: i64 = t1 + 1; let tl: i64 = t2 - ts
61 let v: i64 = tg_pint(log, t2 + 1, i)
62 var found: i64 = 0 - 1; var t: i64 = 0
63 while t < nt { if tg_eqn(tbuf, toff[t], tlen[t], log, ts, tl) == 1 { found = t; t = nt } else { t = t + 1 } }
64 if found >= 0 { tvv[found] = v } else { if nt < 512 { if tb + tl < K_MAGIC_16384 {
65 toff[nt] = tb; var k: i64 = 0; while k < tl { tbuf[tb] = log[ts+k]; tb = tb + 1; k = k + 1 }
66 tlen[nt] = tl; tvv[nt] = v; nt = nt + 1
67 } } }
68 }
69 } }
70 ls = i + 1
71 }
72 i = i + 1
73 }
74 var o: i64 = 0; out[o] = 91 as u8; o = o + 1
75 var first: i64 = 1; var t: i64 = 0
76 while t < nt {
77 if tvv[t] == 1 {
78 if first == 0 { out[o] = 44 as u8; o = o + 1 } first = 0
79 out[o] = 34 as u8; o = o + 1
80 var k: i64 = 0; while k < tlen[t] { out[o] = tbuf[toff[t]+k]; o = o + 1; k = k + 1 }
81 out[o] = 34 as u8; o = o + 1
82 }
83 t = t + 1
84 }
85 out[o] = 93 as u8; o = o + 1
86 return o
87}
88// emit JSON [id,...] of videos CURRENTLY tagged (tag,taglen) (last-wins, v=1, ascending by first-seen).
89func tg_ids_for_tag(log: *u8, sz: i64, tag: *u8, taglen: i64, out: *u8) -> i64 {
90 let ids: *i64 = sys_mmap(8*K_MAGIC_65536) as *i64
91 let vvs: *i64 = sys_mmap(8*K_MAGIC_65536) as *i64
92 let t1p: *i64 = sys_mmap(16) as *i64
93 let t2p: *i64 = sys_mmap(16) as *i64
94 var nid: i64 = 0
95 var i: i64 = 0; var ls: i64 = 0
96 while i <= sz {
97 var nl: i64 = 0; if i == sz { nl = 1 } else { if log[i]==(10 as u8) { nl = 1 } }
98 if nl == 1 {
99 if i > ls { if tg_tabs(log, ls, i, t1p, t2p) == 1 {
100 let t1: i64 = t1p[0]; let t2: i64 = t2p[0]
101 let ts: i64 = t1 + 1; let tl: i64 = t2 - ts
102 if tg_eqn(log, ts, tl, tag, 0, taglen) == 1 {
103 let lid: i64 = tg_pint(log, ls, t1)
104 let v: i64 = tg_pint(log, t2 + 1, i)
105 var found: i64 = 0 - 1; var t: i64 = 0
106 while t < nid { if ids[t] == lid { found = t; t = nid } else { t = t + 1 } }
107 if found >= 0 { vvs[found] = v } else { if nid < K_MAGIC_65536 { ids[nid] = lid; vvs[nid] = v; nid = nid + 1 } }
108 }
109 } }
110 ls = i + 1
111 }
112 i = i + 1
113 }
114 var o: i64 = 0; out[o] = 91 as u8; o = o + 1
115 var first: i64 = 1; var t: i64 = 0
116 while t < nid {
117 if vvs[t] == 1 {
118 if first == 0 { out[o] = 44 as u8; o = o + 1 } first = 0
119 o = tg_emit_u(out, o, ids[t])
120 }
121 t = t + 1
122 }
123 out[o] = 93 as u8; o = o + 1
124 return o
125}
126// emit JSON ["tag",...] of the CURRENTLY-applied distinct tags (first-seen order; a tag removed from every
127// video is excluded via the tg_ids_for_tag non-empty check). The all-tags picker; clicking filters via /api/tagged.
128func tg_all_tags(log: *u8, sz: i64, out: *u8) -> i64 {
129 let tbuf: *u8 = sys_mmap(K_MAGIC_65536)
130 let toff: *i64 = sys_mmap(8*K_MAGIC_4096) as *i64
131 let tlen: *i64 = sys_mmap(8*K_MAGIC_4096) as *i64
132 let t1p: *i64 = sys_mmap(16) as *i64
133 let t2p: *i64 = sys_mmap(16) as *i64
134 var nt: i64 = 0; var tb: i64 = 0
135 var i: i64 = 0; var ls: i64 = 0
136 while i <= sz {
137 var nl: i64 = 0; if i == sz { nl = 1 } else { if log[i]==(10 as u8) { nl = 1 } }
138 if nl == 1 {
139 if i > ls { if tg_tabs(log, ls, i, t1p, t2p) == 1 {
140 let ts: i64 = t1p[0] + 1; let tl: i64 = t2p[0] - ts
141 var found: i64 = 0 - 1; var t: i64 = 0
142 while t < nt { if tg_eqn(tbuf, toff[t], tlen[t], log, ts, tl) == 1 { found = t; t = nt } else { t = t + 1 } }
143 if found < 0 { if nt < K_MAGIC_4096 { if tb + tl < K_MAGIC_65536 {
144 toff[nt] = tb; var k: i64 = 0; while k < tl { tbuf[tb] = log[ts+k]; tb = tb + 1; k = k + 1 }
145 tlen[nt] = tl; nt = nt + 1
146 } } }
147 } }
148 ls = i + 1
149 }
150 i = i + 1
151 }
152 let tmp: *u8 = sys_mmap(K_MAGIC_1048576)
153 var o: i64 = 0; out[o] = 91 as u8; o = o + 1
154 var first: i64 = 1; var tt: i64 = 0
155 while tt < nt {
156 let il: i64 = tg_ids_for_tag(log, sz, ((tbuf as i64)+toff[tt]) as *u8, tlen[tt], tmp)
157 if il > 2 {
158 if first == 0 { out[o] = 44 as u8; o = o + 1 } first = 0
159 out[o] = 34 as u8; o = o + 1
160 var k: i64 = 0; while k < tlen[tt] { out[o] = tbuf[toff[tt]+k]; o = o + 1; k = k + 1 }
161 out[o] = 34 as u8; o = o + 1
162 }
163 tt = tt + 1
164 }
165 out[o] = 93 as u8; o = o + 1
166 return o
167}
168// format a tag op line "<id>\t<tag>\t<v>\n" into buf; returns length.
169func tg_op_line(buf: *u8, id: i64, tag: *u8, taglen: i64, v: i64) -> i64 {
170 var o: i64 = tg_emit_u(buf, 0, id)
171 buf[o] = 9 as u8; o = o + 1
172 var k: i64 = 0; while k < taglen { buf[o] = tag[k]; o = o + 1; k = k + 1 }
173 buf[o] = 9 as u8; o = o + 1
174 if v == 0 { buf[o] = 48 as u8 } else { buf[o] = 49 as u8 } o = o + 1
175 buf[o] = 10 as u8; o = o + 1
176 return o
177}
178// ---- STRING-KEYED variants (the id is an arbitrary string: an int video lineno OR a 69-char image cid) ----
179// These subsume the integer ones (an int id "5" is a valid string id), so videos AND images can share ONE
180// store. Added alongside (non-breaking) so the proven int path + the live gallery are untouched until migrated.
181func tg_op_line_s(buf: *u8, idp: *u8, idlen: i64, tag: *u8, taglen: i64, v: i64) -> i64 {
182 var o: i64 = 0
183 var c: i64 = 0; while c < idlen { buf[o] = idp[c]; o = o + 1; c = c + 1 }
184 buf[o] = 9 as u8; o = o + 1
185 var k: i64 = 0; while k < taglen { buf[o] = tag[k]; o = o + 1; k = k + 1 }
186 buf[o] = 9 as u8; o = o + 1
187 if v == 0 { buf[o] = 48 as u8 } else { buf[o] = 49 as u8 } o = o + 1
188 buf[o] = 10 as u8; o = o + 1
189 return o
190}
191// emit JSON ["tag",...] of the CURRENT tags for the string id (idp,idlen) (last-wins, v=1).
192func tg_tags_for_id_s(log: *u8, sz: i64, idp: *u8, idlen: i64, out: *u8) -> i64 {
193 let tbuf: *u8 = sys_mmap(K_MAGIC_16384)
194 let toff: *i64 = sys_mmap(8*512) as *i64
195 let tlen: *i64 = sys_mmap(8*512) as *i64
196 let tvv: *i64 = sys_mmap(8*512) as *i64
197 let t1p: *i64 = sys_mmap(16) as *i64
198 let t2p: *i64 = sys_mmap(16) as *i64
199 var nt: i64 = 0; var tb: i64 = 0
200 var i: i64 = 0; var ls: i64 = 0
201 while i <= sz {
202 var nl: i64 = 0; if i == sz { nl = 1 } else { if log[i]==(10 as u8) { nl = 1 } }
203 if nl == 1 {
204 if i > ls { if tg_tabs(log, ls, i, t1p, t2p) == 1 {
205 let t1: i64 = t1p[0]; let t2: i64 = t2p[0]
206 if tg_eqn(log, ls, t1 - ls, idp, 0, idlen) == 1 {
207 let ts: i64 = t1 + 1; let tl: i64 = t2 - ts
208 let v: i64 = tg_pint(log, t2 + 1, i)
209 var found: i64 = 0 - 1; var t: i64 = 0
210 while t < nt { if tg_eqn(tbuf, toff[t], tlen[t], log, ts, tl) == 1 { found = t; t = nt } else { t = t + 1 } }
211 if found >= 0 { tvv[found] = v } else { if nt < 512 { if tb + tl < K_MAGIC_16384 {
212 toff[nt] = tb; var k: i64 = 0; while k < tl { tbuf[tb] = log[ts+k]; tb = tb + 1; k = k + 1 }
213 tlen[nt] = tl; tvv[nt] = v; nt = nt + 1
214 } } }
215 }
216 } }
217 ls = i + 1
218 }
219 i = i + 1
220 }
221 var o: i64 = 0; out[o] = 91 as u8; o = o + 1
222 var first: i64 = 1; var t: i64 = 0
223 while t < nt {
224 if tvv[t] == 1 {
225 if first == 0 { out[o] = 44 as u8; o = o + 1 } first = 0
226 out[o] = 34 as u8; o = o + 1
227 var k: i64 = 0; while k < tlen[t] { out[o] = tbuf[toff[t]+k]; o = o + 1; k = k + 1 }
228 out[o] = 34 as u8; o = o + 1
229 }
230 t = t + 1
231 }
232 out[o] = 93 as u8; o = o + 1
233 return o
234}
235// emit JSON ["id",...] (QUOTED string ids) of items CURRENTLY carrying the tag (last-wins, dedup by id string).
236func tg_ids_for_tag_s(log: *u8, sz: i64, tag: *u8, taglen: i64, out: *u8) -> i64 {
237 let ibuf: *u8 = sys_mmap(K_MAGIC_2097152)
238 let ioff: *i64 = sys_mmap(8*K_MAGIC_65536) as *i64
239 let ilen: *i64 = sys_mmap(8*K_MAGIC_65536) as *i64
240 let ivv: *i64 = sys_mmap(8*K_MAGIC_65536) as *i64
241 let t1p: *i64 = sys_mmap(16) as *i64
242 let t2p: *i64 = sys_mmap(16) as *i64
243 var nid: i64 = 0; var ib: i64 = 0
244 var i: i64 = 0; var ls: i64 = 0
245 while i <= sz {
246 var nl: i64 = 0; if i == sz { nl = 1 } else { if log[i]==(10 as u8) { nl = 1 } }
247 if nl == 1 {
248 if i > ls { if tg_tabs(log, ls, i, t1p, t2p) == 1 {
249 let t1: i64 = t1p[0]; let t2: i64 = t2p[0]
250 let ts: i64 = t1 + 1; let tl: i64 = t2 - ts
251 if tg_eqn(log, ts, tl, tag, 0, taglen) == 1 {
252 let idl: i64 = t1 - ls
253 let v: i64 = tg_pint(log, t2 + 1, i)
254 var found: i64 = 0 - 1; var t: i64 = 0
255 while t < nid { if tg_eqn(ibuf, ioff[t], ilen[t], log, ls, idl) == 1 { found = t; t = nid } else { t = t + 1 } }
256 if found >= 0 { ivv[found] = v } else { if nid < K_MAGIC_65536 { if ib + idl < K_MAGIC_2097152 {
257 ioff[nid] = ib; var k: i64 = 0; while k < idl { ibuf[ib] = log[ls+k]; ib = ib + 1; k = k + 1 }
258 ilen[nid] = idl; ivv[nid] = v; nid = nid + 1
259 } } }
260 }
261 } }
262 ls = i + 1
263 }
264 i = i + 1
265 }
266 var o: i64 = 0; out[o] = 91 as u8; o = o + 1
267 var first: i64 = 1; var t: i64 = 0
268 while t < nid {
269 if ivv[t] == 1 {
270 if first == 0 { out[o] = 44 as u8; o = o + 1 } first = 0
271 out[o] = 34 as u8; o = o + 1
272 var k: i64 = 0; while k < ilen[t] { out[o] = ibuf[ioff[t]+k]; o = o + 1; k = k + 1 }
273 out[o] = 34 as u8; o = o + 1
274 }
275 t = t + 1
276 }
277 out[o] = 93 as u8; o = o + 1
278 return o
279}
280// CURRENT distinct tags via the STRING-keyed current-check (correct for image cids: the int tg_all_tags
281// collapses every cid to id 0, mishandling a multi-cid same-tag removal). /api/alltags uses this.
282func tg_all_tags_s(log: *u8, sz: i64, out: *u8) -> i64 {
283 let tbuf: *u8 = sys_mmap(K_MAGIC_65536)
284 let toff: *i64 = sys_mmap(8*K_MAGIC_4096) as *i64
285 let tlen: *i64 = sys_mmap(8*K_MAGIC_4096) as *i64
286 let t1p: *i64 = sys_mmap(16) as *i64
287 let t2p: *i64 = sys_mmap(16) as *i64
288 var nt: i64 = 0; var tb: i64 = 0
289 var i: i64 = 0; var ls: i64 = 0
290 while i <= sz {
291 var nl: i64 = 0; if i == sz { nl = 1 } else { if log[i]==(10 as u8) { nl = 1 } }
292 if nl == 1 {
293 if i > ls { if tg_tabs(log, ls, i, t1p, t2p) == 1 {
294 let ts: i64 = t1p[0] + 1; let tl: i64 = t2p[0] - ts
295 var found: i64 = 0 - 1; var t: i64 = 0
296 while t < nt { if tg_eqn(tbuf, toff[t], tlen[t], log, ts, tl) == 1 { found = t; t = nt } else { t = t + 1 } }
297 if found < 0 { if nt < K_MAGIC_4096 { if tb + tl < K_MAGIC_65536 {
298 toff[nt] = tb; var k: i64 = 0; while k < tl { tbuf[tb] = log[ts+k]; tb = tb + 1; k = k + 1 }
299 tlen[nt] = tl; nt = nt + 1
300 } } }
301 } }
302 ls = i + 1
303 }
304 i = i + 1
305 }
306 let tmp: *u8 = sys_mmap(K_MAGIC_1048576)
307 var o: i64 = 0; out[o] = 91 as u8; o = o + 1
308 var first: i64 = 1; var tt: i64 = 0
309 while tt < nt {
310 let il: i64 = tg_ids_for_tag_s(log, sz, ((tbuf as i64)+toff[tt]) as *u8, tlen[tt], tmp)
311 if il > 2 {
312 if first == 0 { out[o] = 44 as u8; o = o + 1 } first = 0
313 out[o] = 34 as u8; o = o + 1
314 var k: i64 = 0; while k < tlen[tt] { out[o] = tbuf[toff[tt]+k]; o = o + 1; k = k + 1 }
315 out[o] = 34 as u8; o = o + 1
316 }
317 tt = tt + 1
318 }
319 out[o] = 93 as u8; o = o + 1
320 return o
321}