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}