code wiki / _hdl_build / nx_web_ingest.nx
nx_web_ingest.nx source
↩ module page · 235 lines · 11769 B
1// nx_web_ingest.nx -- OPEN-WEB front of nishi search: BFS-crawl the REAL web (sovereign TLS-1.3 + Mozilla CA,
2// polite, simhash near-dup killed) and ingest each kept page STRAIGHT into the shared "web" seg_store shard
3// (dp-web-pub-): doc:<cid> = the page's extracted text, url:<cid> = its ABSOLUTE url -> the /search?scope=web
4// SERP links results to the real pages. Composes the PROVEN pieces only: nx_crawl_web's fetch/link spine +
5// nx_corpus_ingest's writer/key/hash mechanics (ci_hash / ci_mkurlkey / fresh-segid batching, gate 7/7).
6// usage: nx_web_ingest <seed-url> <max_pages>
7// Bounded by max_pages AND the known per-process certloop budget (~19 fetches) -- crawl-at-scale = many small
8// runs, each committing its own segments (append-only, idempotent by content cid). license_tier: ORIGINAL
9import "nx_corpus_ingest.nx" // ci_hash / ci_mkurlkey / dss_prefix / dss_mkkey / seg_store (transitively)
10import "nx_x509_trust_store.nx"
11import "nx_trust_store_load_from_certdata.nx"
12import "nx_https_fetch_follow.nx"
13import "nx_simhash.nx"
14const K_MAGIC_8192: i64 = 8192
15const K_MAGIC_4194304: i64 = 4194304
16const K_MAGIC_8388608: i64 = 8388608
17const K_MAGIC_1048576: i64 = 1048576
18const K_MAGIC_2048: i64 = 2048
19
20func wi_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
21func wi_num(v: i64) -> i64 {
22 let bb: *u8 = sys_mmap(28); var m: i64 = v
23 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
24 let t: *u8 = sys_mmap(28); var k: i64 = 0
25 if m == 0 { t[0] = 48 as u8; k = 1 }
26 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
27 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
28 sys_write(1, bb, k); return 0
29}
30func wi_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
31func wi_atoi(s: *u8) -> i64 { var v: i64 = 0; var i: i64 = 0; while s[i] != (0 as u8) { let c: i64 = s[i] as i64; if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } i = i + 1 } return v }
32
33// scheme://host base from the seed (relative-link resolution) -- mirrors nx_crawl_web.cw_base
34func wi_base(url: *u8, out: *u8) -> i64 {
35 let n: i64 = wi_len(url)
36 var schemeend: i64 = 0
37 var i: i64 = 0
38 var hit: i64 = 0
39 while hit == 0 {
40 if i + 2 >= n { hit = 1 } else {
41 if url[i] == (58 as u8) { if url[i+1] == (47 as u8) { if url[i+2] == (47 as u8) { schemeend = i + 3; hit = 1 } } }
42 if hit == 0 { i = i + 1 }
43 }
44 }
45 var e: i64 = schemeend
46 var go: i64 = 1
47 while go == 1 { if e >= n { go = 0 } else { if url[e] == (47 as u8) { go = 0 } else { e = e + 1 } } }
48 var k: i64 = 0
49 while k < e { out[k] = url[k]; k = k + 1 }
50 out[e] = 0 as u8
51 return e
52}
53func wi_eqn(a: *u8, alen: i64, b: *u8) -> i64 {
54 var i: i64 = 0; while i < alen { if a[i] != b[i] { return 0 } i = i + 1 }
55 if b[alen] != (0 as u8) { return 0 }
56 return 1
57}
58func wi_enqueue(url: *u8, ulen: i64, seen: **u8, nseen: *i64, queue: **u8, qt: *i64, cap: i64) -> i64 {
59 var s: i64 = 0; while s < nseen[0] { if wi_eqn(url, ulen, seen[s]) == 1 { return 0 } s = s + 1 }
60 if nseen[0] >= cap { return 0 }
61 let nu: *u8 = sys_mmap(ulen + 1); var i: i64 = 0; while i < ulen { nu[i] = url[i]; i = i + 1 } nu[ulen] = 0 as u8
62 seen[nseen[0]] = nu; queue[qt[0]] = nu; nseen[0] = nseen[0] + 1; qt[0] = qt[0] + 1
63 return 1
64}
65func wi_pre(h: *u8, hlen: i64, off: i64, lit: *u8, litlen: i64) -> i64 {
66 if off + litlen > hlen { return 0 }
67 var k: i64 = 0; while k < litlen { if h[off+k] != lit[k] { return 0 } k = k + 1 } return 1
68}
69func wi_lc(c: i64) -> i64 { if c >= 0x41 { if c <= 0x5a { return c + 0x20 } } return c }
70func wi_href_at(h: *u8, hlen: i64, off: i64) -> i64 {
71 if off + 5 > hlen { return 0 }
72 if wi_lc(h[off] as i64) != 0x68 { return 0 }
73 if wi_lc(h[off+1] as i64) != 0x72 { return 0 }
74 if wi_lc(h[off+2] as i64) != 0x65 { return 0 }
75 if wi_lc(h[off+3] as i64) != 0x66 { return 0 }
76 if (h[off+4] as i64) != 0x3d { return 0 }
77 return 1
78}
79// extract + resolve + enqueue outbound links (absolute http(s) + root-relative)
80func wi_links(h: *u8, hlen: i64, base: *u8, blen: i64, seen: **u8, nseen: *i64, queue: **u8, qt: *i64, cap: i64) -> i64 {
81 var found: i64 = 0
82 let scratch: *u8 = sys_mmap(K_MAGIC_8192)
83 var i: i64 = 0
84 while i < hlen {
85 var step: i64 = 1
86 if wi_href_at(h, hlen, i) == 1 {
87 let q: i64 = h[i+5] as i64
88 var quoted: i64 = 0
89 if q == 0x22 { quoted = 1 }
90 if q == 0x27 { quoted = 1 }
91 if quoted == 1 {
92 let cs: i64 = i + 6
93 var e: i64 = cs
94 var run: i64 = 1
95 while run == 1 { run = 0; if e < hlen { if (h[e] as i64) != q { e = e + 1; run = 1 } } }
96 let clen: i64 = e - cs
97 if clen > 0 {
98 if wi_pre(h, hlen, cs, "https://" as *u8, 8) == 1 {
99 if wi_enqueue(((h as i64)+cs) as *u8, clen, seen, nseen, queue, qt, cap) == 1 { found = found + 1 }
100 } else { if wi_pre(h, hlen, cs, "http://" as *u8, 7) == 1 {
101 if wi_enqueue(((h as i64)+cs) as *u8, clen, seen, nseen, queue, qt, cap) == 1 { found = found + 1 }
102 } else {
103 if (h[cs] as i64) == 0x2f {
104 var protorel: i64 = 0
105 if clen >= 2 { if (h[cs+1] as i64) == 0x2f { protorel = 1 } }
106 if protorel == 0 { if blen + clen + 1 < K_MAGIC_8192 {
107 var b: i64 = 0; while b < blen { scratch[b] = base[b]; b = b + 1 }
108 var c: i64 = 0; while c < clen { scratch[blen+c] = h[cs+c]; c = c + 1 }
109 scratch[blen+clen] = 0 as u8
110 if wi_enqueue(scratch, blen + clen, seen, nseen, queue, qt, cap) == 1 { found = found + 1 }
111 } }
112 }
113 } }
114 }
115 step = (e - i) + 1
116 }
117 }
118 i = i + step
119 }
120 return found
121}
122
123func main(argc: i64, argv: *i64) -> i64 {
124 if argc < 3 { wi_puts("usage: nx_web_ingest <seed-url> <max_pages>\n" as *u8); return 1 }
125 let seed: *u8 = argv[1] as *u8
126 let max_pages: i64 = wi_atoi(argv[2] as *u8)
127 let r: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt" as *u8, 512, K_MAGIC_4194304)
128 if r <= 0 { wi_puts("certdata load failed\n" as *u8); return 2 }
129 let store: *TrustStore = r as *TrustStore
130 wi_puts("=== nx_web_ingest: crawl -> dp-web-pub- (sovereign open-web search corpus) ===\n" as *u8)
131
132 let prefix: *u8 = sys_mmap(512)
133 dss_prefix("web" as *u8, prefix)
134 // fresh segid past the manifest max (append-only, never clobber)
135 let segs: *i64 = sys_mmap(256 * 8) as *i64
136 let nseg: i64 = ss_manifest_file(prefix, "manifest.txt" as *u8, segs)
137 var segid: i64 = 1
138 var si: i64 = 0
139 // ROOT FIX seq1730 (id 1785450987): segs[] holds POINTERS to seg-<id> name strings
140 // (nx_seg_store.nx:1234 stores segs[cnt] = name as i64), NOT ids -- so segs[si] + 1 produced
141 // MMAP_ADDRESS+1 (~1.4e14), the pointer-shaped poison that PINS a plane forever: every later
142 // epoch id sorts BELOW it in supersede order and its rows are silently shadowed while rc=0.
143 // Parse the DIGITS, as nx_web_shard_compact.nx:55-58 already does on this SAME array.
144 while si < nseg {
145 let sg_nm: *u8 = segs[si] as *u8
146 var sg_v: i64 = 0
147 var sg_ci: i64 = 0
148 while sg_nm[sg_ci] != (0 as u8) { let sg_c: i64 = sg_nm[sg_ci] as i64; if sg_c >= 48 { if sg_c <= 57 { sg_v = sg_v * 10 + (sg_c - 48) } } sg_ci = sg_ci + 1 }
149 if sg_v >= segid { segid = sg_v + 1 }
150 si = si + 1
151 }
152 let h: *i64 = ss_open(prefix)
153 let pbox: *i64 = sys_mmap(16) as *i64
154 let lbox: *i64 = sys_mmap(16) as *i64
155
156 let cap: i64 = K_MAGIC_8388608
157 let out: *u8 = sys_mmap(cap)
158 let tcap: i64 = K_MAGIC_1048576
159 let text: *u8 = sys_mmap(tcap)
160 let status: *i64 = sys_mmap(8) as *i64
161 let QCAP: i64 = 512
162 let queue: **u8 = sys_mmap(QCAP * 8) as **u8
163 let seen: **u8 = sys_mmap(QCAP * 8) as **u8
164 let qt: *i64 = sys_mmap(8) as *i64; qt[0] = 0
165 let nseen: *i64 = sys_mmap(8) as *i64; nseen[0] = 0
166 var qh: i64 = 0
167 let keptfp: *i64 = sys_mmap(128 * 8) as *i64
168 let base: *u8 = sys_mmap(K_MAGIC_2048)
169 let blen: i64 = wi_base(seed, base)
170 wi_enqueue(seed, wi_len(seed), seen, nseen, queue, qt, QCAP)
171
172 let key: *u8 = sys_mmap(64)
173 let ukey: *u8 = sys_mmap(64)
174 var w: *i64 = ss_begin()
175 var crawled: i64 = 0
176 var ingested: i64 = 0
177 var present: i64 = 0
178 var segments: i64 = 0
179 var running: i64 = 1
180 while running == 1 {
181 if qh >= qt[0] { running = 0 }
182 if crawled >= max_pages { running = 0 }
183 if running == 1 {
184 let url: *u8 = queue[qh]; qh = qh + 1
185 sys_sleep_ms(350)
186 let n: i64 = nx_https_fetch_follow(url, store, out, cap, 6, status)
187 if n > 0 { if status[0] == 200 {
188 let tlen: i64 = nx_html_to_text(out, n, text, tcap)
189 if tlen >= CI_MINDOC {
190 let fp: i64 = nx_simhash_fingerprint(text, tlen)
191 var dup: i64 = 0
192 var k: i64 = 0
193 while k < crawled { if nx_simhash_hamming(fp, keptfp[k]) <= 4 { dup = 1 } k = k + 1 }
194 if dup == 0 {
195 if crawled < 128 { keptfp[crawled] = fp }
196 crawled = crawled + 1
197 var tn: i64 = tlen
198 if tn > CI_DOCCAP { tn = CI_DOCCAP }
199 let cid: i64 = ci_hash(text, tn)
200 dss_mkkey(cid, key)
201 var already: i64 = 0
202 if (h as i64) != 0 { if ss_hget(h, key, pbox, lbox) == 1 { already = 1 } }
203 if already == 1 { present = present + 1 } else {
204 if ss_add(w, 1, key, text, tn) < 0 {
205 if ss_commit(prefix, w, segid) == 0 { segments = segments + 1 }
206 segid = segid + 1
207 w = ss_begin()
208 ss_add(w, 1, key, text, tn)
209 }
210 ci_mkurlkey(cid, ukey)
211 if ss_add(w, 1, ukey, url, wi_len(url)) < 0 {
212 if ss_commit(prefix, w, segid) == 0 { segments = segments + 1 }
213 segid = segid + 1
214 w = ss_begin()
215 ss_add(w, 1, ukey, url, wi_len(url))
216 }
217 ingested = ingested + 1
218 wi_puts(" ingested #" as *u8); wi_num(ingested); wi_puts(" " as *u8); wi_puts(url); wi_puts(" (" as *u8); wi_num(tn); wi_puts(" chars)\n" as *u8)
219 }
220 wi_links(out, n, base, blen, seen, nseen, queue, qt, QCAP)
221 }
222 }
223 } }
224 }
225 }
226 if w[1] > 0 { if ss_commit(prefix, w, segid) == 0 { segments = segments + 1 } }
227 wi_puts("WEB-INGEST done: crawled=" as *u8); wi_num(crawled)
228 wi_puts(" ingested=" as *u8); wi_num(ingested)
229 wi_puts(" already_present=" as *u8); wi_num(present)
230 wi_puts(" segments=" as *u8); wi_num(segments)
231 wi_puts(" -> dp-web-pub-\n" as *u8)
232 if ingested + present >= 1 { wi_puts("WEB-INGEST GREEN\n" as *u8); return 0 }
233 wi_puts("WEB-INGEST RED (nothing ingested)\n" as *u8)
234 return 3
235}