code wiki / _hdl_build / nx_arcade_serve.nx
nx_arcade_serve.nx source
↩ module page · 431 lines · 22932 B
1// nx_arcade_serve.nx -- SOVEREIGN static HTTP server for the Nishi arcade (replaces the
2// python host hack). Pure Nishi: socket/bind/listen/accept + read-file-from-disk + serve,
3// no node/python/3rd-party. Serves the canvas page + the Nishi-COMPILED game wasm so the
4// operator plays in a browser via a fully sovereign toolchain (nx->wat(nxc2)->wasm(Nishi
5// nx_wat_compiler)->Nishi server). The only non-Nishi piece is the browser + the ~40-line
6// canvas shim (the named last-mile debt -> future Nishi browser). Built native by Nishi's
7// own toolchain. Run from repo root. license_tier: ORIGINAL
8import "nx_syscalls.nx"
9import "nx_native_config.nx" // sweep: serve the games catalog from the SOVEREIGN native store (games-reg-), no loose .tsv
10import "nx_geo_places.nx" // GEO-021 fuzzy geocode (geo_fuzzy_best) for /geocode + /route name resolve
11import "nx_geo_route.nx" // GEO-008 integer Dijkstra (geo_dijkstra, geo_path) for /route
12import "nx_geo_distance.nx" // GEO-003 geo_distance_m for integer edge weights
13const K_MAGIC_42360000: i64 = 42360000
14const K_MAGIC_71060000: i64 = 71060000
15const K_MAGIC_41824000: i64 = 41824000
16const K_MAGIC_71412000: i64 = 71412000
17const K_MAGIC_41763000: i64 = 41763000
18const K_MAGIC_72685000: i64 = 72685000
19const K_MAGIC_40712800: i64 = 40712800
20const K_MAGIC_74006000: i64 = 74006000
21const K_MAGIC_40735700: i64 = 40735700
22const K_MAGIC_74172400: i64 = 74172400
23const K_MAGIC_40217000: i64 = 40217000
24const K_MAGIC_74763000: i64 = 74763000
25const K_MAGIC_39952600: i64 = 39952600
26const K_MAGIC_75165200: i64 = 75165200
27const K_MAGIC_39290400: i64 = 39290400
28const K_MAGIC_76612200: i64 = 76612200
29const K_MAGIC_38900000: i64 = 38900000
30const K_MAGIC_77036000: i64 = 77036000
31const K_MAGIC_43661000: i64 = 43661000
32const K_MAGIC_70255000: i64 = 70255000
33const K_MAGIC_42652000: i64 = 42652000
34const K_MAGIC_73757000: i64 = 73757000
35const K_MAGIC_42886000: i64 = 42886000
36const K_MAGIC_78878000: i64 = 78878000
37const K_MAGIC_40273000: i64 = 40273000
38const K_MAGIC_76884000: i64 = 76884000
39const K_MAGIC_40440600: i64 = 40440600
40const K_MAGIC_79995900: i64 = 79995900
41const K_MAGIC_39745800: i64 = 39745800
42const K_MAGIC_75546600: i64 = 75546600
43const K_MAGIC_37540700: i64 = 37540700
44const K_MAGIC_77436000: i64 = 77436000
45const K_MAGIC_36850800: i64 = 36850800
46const K_MAGIC_76285900: i64 = 76285900
47const K_MAGIC_7700: i64 = 7700
48const K_MAGIC_8192: i64 = 8192
49const K_MAGIC_1024: i64 = 1024
50const K_MAGIC_65536: i64 = 65536
51const K_MAGIC_4096: i64 = 4096
52
53func as_find(buf: *u8, n: i64, pat: *u8, plen: i64) -> i64 {
54 var i: i64 = 0
55 while i + plen <= n {
56 var j: i64 = 0
57 var m: i64 = 1
58 while j < plen { if buf[i + j] != pat[j] { m = 0; j = plen } else { j = j + 1 } }
59 if m == 1 { return i }
60 i = i + 1
61 }
62 return 0 - 1
63}
64func as_path(req: *u8, n: i64, out: *u8) -> i64 {
65 let g: i64 = as_find(req, n, "GET " as *u8, 4)
66 if g < 0 { out[0] = 0 as u8; return 0 }
67 var p: i64 = g + 4
68 var w: i64 = 0
69 var go: i64 = 1
70 while go == 1 {
71 if p >= n { go = 0 } else {
72 if req[p] == (32 as u8) { go = 0 } else { out[w] = req[p]; w = w + 1; p = p + 1 }
73 }
74 }
75 out[w] = 0 as u8
76 return w
77}
78func as_eq(a: *u8, b: *u8) -> i64 {
79 var i: i64 = 0
80 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
81 if b[i] != (0 as u8) { return 0 }
82 return 1
83}
84func as_starts(s: *u8, pre: *u8) -> i64 {
85 var i: i64 = 0
86 while pre[i] != (0 as u8) { if s[i] != pre[i] { return 0 } i = i + 1 }
87 return 1
88}
89func as_wstr(buf: *u8, off: i64, s: *u8) -> i64 {
90 var i: i64 = 0
91 while s[i] != (0 as u8) { buf[off + i] = s[i]; i = i + 1 }
92 return off + i
93}
94func as_wn(buf: *u8, off: i64, v: i64) -> i64 {
95 var m: i64 = v
96 let tmp: *u8 = sys_mmap(32)
97 var k: i64 = 0
98 if m == 0 { tmp[0] = 48 as u8; k = 1 }
99 while m > 0 { tmp[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
100 var i: i64 = 0
101 while i < k { buf[off + i] = tmp[k - 1 - i]; i = i + 1 }
102 return off + k
103}
104func as_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
105// append NUL-terminated s to dst at off; return off after the written NUL (builds a name-list).
106func as_cat(dst: *u8, off: i64, s: *u8) -> i64 {
107 var i: i64 = 0
108 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 }
109 dst[off + i] = 0 as u8
110 return off + i + 1
111}
112// write a JSON key: "k": (uses byte 34 for the quote, byte 58 for the colon -- no \" escape needed).
113func as_key(buf: *u8, off: i64, k: *u8) -> i64 {
114 var o: i64 = off
115 buf[o] = 34 as u8; o = o + 1
116 o = as_wstr(buf, o, k)
117 buf[o] = 34 as u8; o = o + 1
118 buf[o] = 58 as u8; o = o + 1
119 return o
120}
121// signed decimal (as_wn is unsigned; coords/lon are negative).
122func as_wsn(buf: *u8, off: i64, v: i64) -> i64 {
123 var o: i64 = off
124 var m: i64 = v
125 if m < 0 { buf[o] = 45 as u8; o = o + 1; m = 0 - m }
126 return as_wn(buf, o, m)
127}
128// extract a query-string value: find key (e.g. "q=") in path, copy its value to out, decoding
129// '+' and %20 to space, stopping at '&' or end. Returns length. NUL-terminates out.
130func as_qval(path: *u8, key: *u8, out: *u8) -> i64 {
131 let n: i64 = as_slen(path)
132 let kl: i64 = as_slen(key)
133 var st: i64 = 0 - 1
134 var i: i64 = 0
135 while i + kl <= n {
136 var j: i64 = 0
137 var m: i64 = 1
138 while j < kl { if path[i + j] != key[j] { m = 0; j = kl } else { j = j + 1 } }
139 if m == 1 { st = i + kl; i = n } else { i = i + 1 }
140 }
141 if st < 0 { out[0] = 0 as u8; return 0 }
142 var w: i64 = 0
143 var p: i64 = st
144 while p < n {
145 let c: i64 = path[p] as i64
146 if c == 38 { p = n } else {
147 if c == 43 { out[w] = 32 as u8; w = w + 1; p = p + 1 } else {
148 if c == 37 {
149 if path[p + 1] == (50 as u8) { if path[p + 2] == (48 as u8) { out[w] = 32 as u8; w = w + 1; p = p + 3 } else { out[w] = path[p]; w = w + 1; p = p + 1 } } else { out[w] = path[p]; w = w + 1; p = p + 1 }
150 } else { out[w] = path[p]; w = w + 1; p = p + 1 }
151 }
152 }
153 }
154 out[w] = 0 as u8
155 return w
156}
157// build the shared corridor gazetteer: NUL-separated names into nl, parallel lat/lon arrays. Returns count.
158func as_gaz(nl: *u8, glat: *i64, glon: *i64) -> i64 {
159 var o: i64 = 0
160 o = as_cat(nl, o, "Boston" as *u8)
161 o = as_cat(nl, o, "Providence" as *u8)
162 o = as_cat(nl, o, "Hartford" as *u8)
163 o = as_cat(nl, o, "New York" as *u8)
164 o = as_cat(nl, o, "Newark" as *u8)
165 o = as_cat(nl, o, "Trenton" as *u8)
166 o = as_cat(nl, o, "Philadelphia" as *u8)
167 o = as_cat(nl, o, "Baltimore" as *u8)
168 o = as_cat(nl, o, "Washington DC" as *u8)
169 o = as_cat(nl, o, "Portland" as *u8)
170 o = as_cat(nl, o, "Albany" as *u8)
171 o = as_cat(nl, o, "Buffalo" as *u8)
172 o = as_cat(nl, o, "Harrisburg" as *u8)
173 o = as_cat(nl, o, "Pittsburgh" as *u8)
174 o = as_cat(nl, o, "Wilmington" as *u8)
175 o = as_cat(nl, o, "Richmond" as *u8)
176 o = as_cat(nl, o, "Norfolk" as *u8)
177 nl[o] = 0 as u8
178 glat[0]=K_MAGIC_42360000; glon[0]=0-K_MAGIC_71060000
179 glat[1]=K_MAGIC_41824000; glon[1]=0-K_MAGIC_71412000
180 glat[2]=K_MAGIC_41763000; glon[2]=0-K_MAGIC_72685000
181 glat[3]=K_MAGIC_40712800; glon[3]=0-K_MAGIC_74006000
182 glat[4]=K_MAGIC_40735700; glon[4]=0-K_MAGIC_74172400
183 glat[5]=K_MAGIC_40217000; glon[5]=0-K_MAGIC_74763000
184 glat[6]=K_MAGIC_39952600; glon[6]=0-K_MAGIC_75165200
185 glat[7]=K_MAGIC_39290400; glon[7]=0-K_MAGIC_76612200
186 glat[8]=K_MAGIC_38900000; glon[8]=0-K_MAGIC_77036000
187 glat[9]=K_MAGIC_43661000; glon[9]=0-K_MAGIC_70255000
188 glat[10]=K_MAGIC_42652000; glon[10]=0-K_MAGIC_73757000
189 glat[11]=K_MAGIC_42886000; glon[11]=0-K_MAGIC_78878000
190 glat[12]=K_MAGIC_40273000; glon[12]=0-K_MAGIC_76884000
191 glat[13]=K_MAGIC_40440600; glon[13]=0-K_MAGIC_79995900
192 glat[14]=K_MAGIC_39745800; glon[14]=0-K_MAGIC_75546600
193 glat[15]=K_MAGIC_37540700; glon[15]=0-K_MAGIC_77436000
194 glat[16]=K_MAGIC_36850800; glon[16]=0-K_MAGIC_76285900
195 return 17
196}
197// pointer to the idx-th NUL-separated name in nl (walk past idx NULs).
198func as_name_at(nl: *u8, idx: i64) -> *u8 {
199 var o: i64 = 0
200 var c: i64 = 0
201 while c < idx { while nl[o] != (0 as u8) { o = o + 1 } o = o + 1; c = c + 1 }
202 return (nl + o) as *u8
203}
204// set an undirected graph edge a<->b with weight = integer geodesic meters (GEO-003).
205func as_edge(adj: *i64, n: i64, a: i64, b: i64, glat: *i64, glon: *i64) -> i64 {
206 let w: i64 = geo_distance_m(glat[a], glon[a], glat[b], glon[b])
207 adj[a * n + b] = w
208 adj[b * n + a] = w
209 return 0
210}
211// serve a disk file with content-type; returns 0 ok / -1 not found
212func as_serve(cfd: i64, path: *u8, ctype: *u8) -> i64 {
213 let lenp: *i64 = sys_mmap(16) as *i64
214 let body: *u8 = sys_read_file(path, lenp)
215 if body == (0 as i64) as *u8 { return 0 - 1 }
216 let blen: i64 = lenp[0]
217 let hdr: *u8 = sys_mmap(512)
218 var o: i64 = 0
219 o = as_wstr(hdr, o, "HTTP/1.1 200 OK\r\nContent-Type: " as *u8)
220 o = as_wstr(hdr, o, ctype)
221 o = as_wstr(hdr, o, "\r\nContent-Length: " as *u8)
222 o = as_wn(hdr, o, blen)
223 o = as_wstr(hdr, o, "\r\nConnection: close\r\nAccess-Control-Allow-Origin: *\r\n\r\n" as *u8)
224 sys_write(cfd, hdr, o)
225 sys_write(cfd, body, blen)
226 return 0
227}
228// sweep: reconstruct the games catalog from the SOVEREIGN native store (games-reg-, nx_native_config) into
229// buf; return length. Replaces the loose knowledge/status/published_catalog.tsv read -- the native store is
230// the games SSOT (id/title/engine/path/deployed), so this route no longer touches a flat .tsv.
231func as_games_catalog(buf: *u8) -> i64 {
232 let h: *i64 = ncfg_open("knowledge/store/games-reg-\x00" as *u8)
233 var o: i64 = as_wstr(buf, 0, "# Nishi games catalog -- sovereign native store (games-reg-), no tsv\n# id\ttitle\tengine\tpath\tdeployed\n" as *u8)
234 if (h as i64) == 0 { return o }
235 let cnt: i64 = ncfg_count(h, "game\x00" as *u8)
236 let rk: *i64 = sys_mmap(8*8) as *i64
237 let rv: *i64 = sys_mmap(8*8) as *i64
238 var i: i64 = 0
239 while i < cnt {
240 let nf: i64 = ncfg_row(h, "game\x00" as *u8, i, rk, rv, 8)
241 if nf > 0 {
242 o = as_wstr(buf, o, ncfg_field(rk, rv, nf, "id\x00" as *u8)); buf[o]=(9 as u8); o=o+1
243 o = as_wstr(buf, o, ncfg_field(rk, rv, nf, "title\x00" as *u8)); buf[o]=(9 as u8); o=o+1
244 o = as_wstr(buf, o, ncfg_field(rk, rv, nf, "engine\x00" as *u8)); buf[o]=(9 as u8); o=o+1
245 o = as_wstr(buf, o, ncfg_field(rk, rv, nf, "path\x00" as *u8)); buf[o]=(9 as u8); o=o+1
246 o = as_wstr(buf, o, ncfg_field(rk, rv, nf, "deployed\x00" as *u8)); buf[o]=(10 as u8); o=o+1
247 }
248 i = i + 1
249 }
250 return o
251}
252// serve a prebuilt buffer (mirrors as_serve, but from memory not disk).
253func as_serve_buf(cfd: i64, buf: *u8, blen: i64, ctype: *u8) -> i64 {
254 let hdr: *u8 = sys_mmap(512)
255 var o: i64 = 0
256 o = as_wstr(hdr, o, "HTTP/1.1 200 OK\r\nContent-Type: " as *u8)
257 o = as_wstr(hdr, o, ctype)
258 o = as_wstr(hdr, o, "\r\nContent-Length: " as *u8)
259 o = as_wn(hdr, o, blen)
260 o = as_wstr(hdr, o, "\r\nConnection: close\r\nAccess-Control-Allow-Origin: *\r\n\r\n" as *u8)
261 sys_write(cfd, hdr, o)
262 sys_write(cfd, buf, blen)
263 return 0
264}
265func main() -> i64 {
266 let port: i64 = K_MAGIC_7700
267 let addr: *u8 = sys_mmap(16)
268 addr[0] = 2 as u8; addr[1] = 0 as u8
269 addr[2] = ((port >> 8) & 0xff) as u8; addr[3] = (port & 0xff) as u8
270 addr[4] = 127 as u8; addr[5] = 0 as u8; addr[6] = 0 as u8; addr[7] = 1 as u8
271 var z: i64 = 8
272 while z < 16 { addr[z] = 0 as u8; z = z + 1 }
273 let lfd: i64 = sys_socket(2, 1, 0)
274 if lfd < 0 { sys_write(1, "socket failed\n" as *u8, 14); sys_exit(1); return 1 }
275 let optval: *u8 = sys_mmap(4)
276 optval[0] = 1 as u8; optval[1] = 0 as u8; optval[2] = 0 as u8; optval[3] = 0 as u8
277 sys_setsockopt(lfd, 1, 2, optval, 4)
278 if sys_bind(lfd, addr, 16) < 0 { sys_write(1, "bind failed\n" as *u8, 12); sys_exit(1); return 1 }
279 if sys_listen(lfd, 16) < 0 { sys_write(1, "listen failed\n" as *u8, 14); sys_exit(1); return 1 }
280 sys_write(1, "NISHI ARCADE (sovereign nx server) on http://localhost:7700\n" as *u8, 59)
281 let req: *u8 = sys_mmap(K_MAGIC_8192)
282 let path: *u8 = sys_mmap(K_MAGIC_1024)
283 let nf: *u8 = "HTTP/1.1 404 Not Found\r\nContent-Length: 3\r\nConnection: close\r\n\r\n404" as *u8
284 let rst: *i64 = sys_mmap(16) as *i64 // wait4 status buffer for reaping exited connection handlers
285 var go: i64 = 1
286 while go == 1 {
287 let cfd: i64 = sys_accept(lfd)
288 if cfd >= 0 {
289 let pid: i64 = sys_fork()
290 if pid == 0 {
291 sys_close(lfd)
292 let rn: i64 = sys_read(cfd, req, K_MAGIC_8192)
293 as_path(req, rn, path)
294 var served: i64 = 0
295 if as_eq(path, "/" as *u8) == 1 { served = 1; as_serve(cfd, "web_assets/_game_build/arcade2.html" as *u8, "text/html; charset=utf-8" as *u8) }
296 if as_eq(path, "/dungeon.wasm" as *u8) == 1 { served = 1; as_serve(cfd, "web_assets/_game_build/dungeon.wasm" as *u8, "application/wasm" as *u8) }
297 if as_eq(path, "/pets" as *u8) == 1 { served = 1; as_serve(cfd, "web_assets/_game_build/pets.html" as *u8, "text/html; charset=utf-8" as *u8) }
298 if as_eq(path, "/pets.wasm" as *u8) == 1 { served = 1; as_serve(cfd, "web_assets/_game_build/pets.wasm" as *u8, "application/wasm" as *u8) }
299 if as_eq(path, "/pets3d.png" as *u8) == 1 { served = 1; as_serve(cfd, "web_assets/_game_build/pets3d.png" as *u8, "image/png" as *u8) }
300 if as_eq(path, "/pets3d.bmp" as *u8) == 1 { served = 1; as_serve(cfd, "web_assets/_game_build/pets3d.bmp" as *u8, "image/bmp" as *u8) }
301 if as_eq(path, "/pets3dview" as *u8) == 1 { served = 1; as_serve(cfd, "web_assets/_game_build/pets3dview.html" as *u8, "text/html; charset=utf-8" as *u8) }
302 if as_eq(path, "/maps" as *u8) == 1 { served = 1; as_serve(cfd, "web_assets/_maps_build/maps.html" as *u8, "text/html; charset=utf-8" as *u8) }
303 if as_eq(path, "/nx_geo_wasm.wasm" as *u8) == 1 { served = 1; as_serve(cfd, "web_assets/_maps_build/nx_geo_wasm.wasm" as *u8, "application/wasm" as *u8) }
304 if as_eq(path, "/games" as *u8) == 1 { served = 1; as_serve(cfd, "web_assets/_game_build/games.html" as *u8, "text/html; charset=utf-8" as *u8) }
305 if as_eq(path, "/published_catalog.tsv" as *u8) == 1 { served = 1; let cbuf: *u8 = sys_mmap(K_MAGIC_65536); let clen: i64 = as_games_catalog(cbuf); as_serve_buf(cfd, cbuf, clen, "text/plain; charset=utf-8" as *u8) }
306 if served == 0 { if as_starts(path, "/geocode" as *u8) == 1 {
307 served = 1
308 let q: *u8 = sys_mmap(256)
309 as_qval(path, "q=" as *u8, q)
310 // shared gazetteer (17 cities, GEO-021 fuzzy match).
311 let nl: *u8 = sys_mmap(K_MAGIC_1024)
312 let glat: *i64 = sys_mmap(8 * 17) as *i64
313 let glon: *i64 = sys_mmap(8 * 17) as *i64
314 as_gaz(nl, glat, glon)
315 let gdist: *i64 = sys_mmap(8) as *i64
316 let goff: *i64 = sys_mmap(8) as *i64
317 let gidx: i64 = geo_fuzzy_best(q, nl, gdist, goff)
318 let body: *u8 = sys_mmap(512)
319 var bo: i64 = 0
320 bo = as_wstr(body, bo, "{" as *u8)
321 bo = as_key(body, bo, "name" as *u8)
322 body[bo] = 34 as u8; bo = bo + 1
323 bo = as_wstr(body, bo, (nl + goff[0]) as *u8)
324 body[bo] = 34 as u8; bo = bo + 1
325 bo = as_wstr(body, bo, "," as *u8); bo = as_key(body, bo, "lat" as *u8); bo = as_wsn(body, bo, glat[gidx])
326 bo = as_wstr(body, bo, "," as *u8); bo = as_key(body, bo, "lon" as *u8); bo = as_wsn(body, bo, glon[gidx])
327 bo = as_wstr(body, bo, "," as *u8); bo = as_key(body, bo, "dist" as *u8); bo = as_wsn(body, bo, gdist[0])
328 bo = as_wstr(body, bo, "}" as *u8)
329 let gh: *u8 = sys_mmap(256)
330 var ho: i64 = 0
331 ho = as_wstr(gh, ho, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: " as *u8)
332 ho = as_wn(gh, ho, bo)
333 ho = as_wstr(gh, ho, "\r\nConnection: close\r\nAccess-Control-Allow-Origin: *\r\n\r\n" as *u8)
334 sys_write(cfd, gh, ho)
335 sys_write(cfd, body, bo)
336 } }
337 if served == 0 { if as_starts(path, "/route" as *u8) == 1 {
338 served = 1
339 let qf: *u8 = sys_mmap(256); as_qval(path, "from=" as *u8, qf)
340 let qt: *u8 = sys_mmap(256); as_qval(path, "to=" as *u8, qt)
341 let rnl: *u8 = sys_mmap(K_MAGIC_1024)
342 let rlat: *i64 = sys_mmap(8 * 17) as *i64
343 let rlon: *i64 = sys_mmap(8 * 17) as *i64
344 let rn: i64 = as_gaz(rnl, rlat, rlon)
345 let dfrom: *i64 = sys_mmap(8) as *i64
346 let ofrom: *i64 = sys_mmap(8) as *i64
347 let dto: *i64 = sys_mmap(8) as *i64
348 let oto: *i64 = sys_mmap(8) as *i64
349 let fi: i64 = geo_fuzzy_best(qf, rnl, dfrom, ofrom)
350 let ti: i64 = geo_fuzzy_best(qt, rnl, dto, oto)
351 // road graph over 17 nodes: I-95 spine + inland branch + expanded network (weights=integer m).
352 let adj: *i64 = sys_mmap(8 * 289) as *i64
353 var zz: i64 = 0
354 while zz < 289 { adj[zz] = 0; zz = zz + 1 }
355 as_edge(adj, 17, 0, 1, rlat, rlon) // Boston-Providence
356 as_edge(adj, 17, 1, 3, rlat, rlon) // Providence-NewYork
357 as_edge(adj, 17, 3, 4, rlat, rlon) // NewYork-Newark
358 as_edge(adj, 17, 4, 5, rlat, rlon) // Newark-Trenton
359 as_edge(adj, 17, 5, 6, rlat, rlon) // Trenton-Philadelphia
360 as_edge(adj, 17, 6, 7, rlat, rlon) // Philadelphia-Baltimore (direct)
361 as_edge(adj, 17, 7, 8, rlat, rlon) // Baltimore-Washington
362 as_edge(adj, 17, 3, 2, rlat, rlon) // NewYork-Hartford
363 as_edge(adj, 17, 2, 1, rlat, rlon) // Hartford-Providence
364 as_edge(adj, 17, 0, 9, rlat, rlon) // Boston-Portland
365 as_edge(adj, 17, 3, 10, rlat, rlon) // NewYork-Albany
366 as_edge(adj, 17, 10, 11, rlat, rlon) // Albany-Buffalo
367 as_edge(adj, 17, 6, 12, rlat, rlon) // Philadelphia-Harrisburg
368 as_edge(adj, 17, 12, 13, rlat, rlon) // Harrisburg-Pittsburgh
369 as_edge(adj, 17, 6, 14, rlat, rlon) // Philadelphia-Wilmington
370 as_edge(adj, 17, 14, 7, rlat, rlon) // Wilmington-Baltimore
371 as_edge(adj, 17, 8, 15, rlat, rlon) // Washington-Richmond
372 as_edge(adj, 17, 15, 16, rlat, rlon) // Richmond-Norfolk
373 let rdist: *i64 = sys_mmap(8 * 17) as *i64
374 let rprev: *i64 = sys_mmap(8 * 17) as *i64
375 geo_dijkstra(adj, 17, fi, rdist, rprev)
376 let rpath: *i64 = sys_mmap(8 * 64) as *i64
377 let hops: i64 = geo_path(rprev, fi, ti, rpath)
378 let body: *u8 = sys_mmap(K_MAGIC_4096)
379 var bo: i64 = 0
380 bo = as_wstr(body, bo, "{" as *u8)
381 bo = as_key(body, bo, "from" as *u8); body[bo]=34 as u8; bo=bo+1; bo=as_wstr(body, bo, (rnl + ofrom[0]) as *u8); body[bo]=34 as u8; bo=bo+1
382 bo = as_wstr(body, bo, "," as *u8); bo = as_key(body, bo, "to" as *u8); body[bo]=34 as u8; bo=bo+1; bo=as_wstr(body, bo, (rnl + oto[0]) as *u8); body[bo]=34 as u8; bo=bo+1
383 bo = as_wstr(body, bo, "," as *u8); bo = as_key(body, bo, "dist_m" as *u8); bo = as_wsn(body, bo, rdist[ti])
384 bo = as_wstr(body, bo, "," as *u8); bo = as_key(body, bo, "hops" as *u8); bo = as_wsn(body, bo, hops)
385 bo = as_wstr(body, bo, "," as *u8); bo = as_key(body, bo, "path" as *u8); bo = as_wstr(body, bo, "[" as *u8)
386 var pi: i64 = 0
387 while pi < hops {
388 if pi > 0 { bo = as_wstr(body, bo, "," as *u8) }
389 let nd: i64 = rpath[pi]
390 bo = as_wstr(body, bo, "[" as *u8); bo = as_wsn(body, bo, rlat[nd]); bo = as_wstr(body, bo, "," as *u8); bo = as_wsn(body, bo, rlon[nd]); bo = as_wstr(body, bo, "]" as *u8)
391 pi = pi + 1
392 }
393 bo = as_wstr(body, bo, "]" as *u8)
394 bo = as_wstr(body, bo, "," as *u8); bo = as_key(body, bo, "names" as *u8); bo = as_wstr(body, bo, "[" as *u8)
395 var ni: i64 = 0
396 while ni < hops {
397 if ni > 0 { bo = as_wstr(body, bo, "," as *u8) }
398 body[bo] = 34 as u8; bo = bo + 1
399 bo = as_wstr(body, bo, as_name_at(rnl, rpath[ni]))
400 body[bo] = 34 as u8; bo = bo + 1
401 ni = ni + 1
402 }
403 bo = as_wstr(body, bo, "]}" as *u8)
404 let rh: *u8 = sys_mmap(256)
405 var rho: i64 = 0
406 rho = as_wstr(rh, rho, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: " as *u8)
407 rho = as_wn(rh, rho, bo)
408 rho = as_wstr(rh, rho, "\r\nConnection: close\r\nAccess-Control-Allow-Origin: *\r\n\r\n" as *u8)
409 sys_write(cfd, rh, rho)
410 sys_write(cfd, body, bo)
411 } }
412 if served == 0 { if as_starts(path, "/frame_" as *u8) == 1 {
413 let fp: *u8 = sys_mmap(256)
414 var fk: i64 = as_wstr(fp, 0, "web_assets/_game_build" as *u8)
415 var fpi: i64 = 0
416 while path[fpi] != (0 as u8) { fp[fk] = path[fpi]; fk = fk + 1; fpi = fpi + 1 }
417 fp[fk] = 0 as u8
418 served = 1
419 as_serve(cfd, fp, "image/bmp" as *u8)
420 } }
421 if served == 0 { sys_write(cfd, nf, as_slen(nf)) }
422 sys_close(cfd)
423 sys_exit(0)
424 }
425 sys_close(cfd)
426 while sys_wait4(0 - 1, rst, 1) > 0 { } // REAP exited handlers (WNOHANG=1) -- fixes the zombie-process leak (same class as nx_mp_serve)
427 }
428 }
429 sys_close(lfd)
430 return 0
431}