nx_motion_serve.nx source
↩ module page · 370 lines · 21464 B
1// nx_motion_serve.nx -- /motion AS A TOOL, NOT A BROCHURE (2026-09-06): a visitor uploads a mesh, the sovereign auto-rig
2// rigs it, the page shows it from three sides with its own numbers, a library clip retargets onto it, the result exports,
3// and the operator's ACCEPT or REJECT lands from the same page. The mesh2motion-class surface, on the estate's own organs.
4//
5// nx_motion_serve [port] serve on LOOPBACK (default 18132); the edge proxies /motion to it
6// nx_motion_serve emit <out.html> write the static fallback -- THE SAME RENDERER, the empty form, byte-identical
7//
8// SHAPE, and why (the /math pattern): plain GET and POST forms, no script, no fetch, no client runtime, so it works
9// with JavaScript off, every job is a shareable URL, and there is no third party anywhere in the path. Routing is
10// prefix-agnostic on purpose: the edge forwards /motion/upload and a loopback test sends /upload, and both route the same.
11// The daemon never does the work: it types the upload by MAGIC, writes a digit-named job directory, and spawns the job
12// organ DETACHED (double fork), so accept() is never held by a rig. It reads status rows the job writes and shows them.
13// license_tier: ORIGINAL
14import "nx_syscalls.nx"
15import "nx_http_server.nx"
16import "nx_motion_lib.nx"
17
18const MS_PORT_DEFAULT: i64 = 18132
19const MS_BACKLOG: i64 = 64
20const MS_RESP_RESERVE: i64 = 1024
21const MS_METHOD_GET: i64 = 1
22const MS_METHOD_POST: i64 = 2
23const MS_CELLS_MIN: i64 = 48
24const MS_CELLS_MAX: i64 = 256
25const MS_CELLS_DEFAULT: i64 = 192
26const MS_WORDS_CAP: i64 = 200
27const MS_EXIT_USAGE: i64 = 2
28const MS_REFRESH_HEAD: *u8 = "<meta http-equiv=\"refresh\" content=\"4\">"
29const MS_RIG_ELF: *u8 = "_offc/nx_motion_rig.elf"
30const MS_STORE_ELF: *u8 = "_offc/nx_store_put.elf"
31const MS_ACCEPT_PLANE: *u8 = "knowledge/store/accept-"
32
33func msw(s: *u8) -> i64 { sys_write(1, s, mo_slen(s)); return 0 }
34// one response: status line, type, length, no-store, nosniff, close -- then the body
35func ms_send(cfd: i64, status: *u8, ctype: *u8, body: *u8, n: i64) -> i64 {
36 let buf: *u8 = sys_mmap(n + MS_RESP_RESERVE)
37 var o: i64 = mo_cat(buf, 0, "HTTP/1.1 " as *u8)
38 o = mo_cat(buf, o, status)
39 o = mo_cat(buf, o, "\r\nContent-Type: " as *u8)
40 o = mo_cat(buf, o, ctype)
41 o = mo_cat(buf, o, "\r\nContent-Length: " as *u8)
42 o = mo_num(buf, o, n)
43 o = mo_cat(buf, o, "\r\nCache-Control: no-store\r\nX-Content-Type-Options: nosniff\r\nReferrer-Policy: strict-origin-when-cross-origin\r\nConnection: close\r\n\r\n" as *u8)
44 o = mo_catb(buf, o, body, n)
45 nx_http_server_send_response(cfd, buf, o)
46 sys_munmap(buf, n + MS_RESP_RESERVE)
47 return 0
48}
49func ms_text(cfd: i64, status: *u8, msg: *u8) -> i64 { return ms_send(cfd, status, "text/plain; charset=utf-8" as *u8, msg, mo_slen(msg)) }
50func ms_redirect(cfd: i64, loc: *u8) -> i64 {
51 let buf: *u8 = sys_mmap(MS_RESP_RESERVE)
52 var o: i64 = mo_cat(buf, 0, "HTTP/1.1 303 See Other\r\nLocation: " as *u8)
53 o = mo_cat(buf, o, loc)
54 o = mo_cat(buf, o, "\r\nContent-Length: 0\r\nCache-Control: no-store\r\nConnection: close\r\n\r\n" as *u8)
55 nx_http_server_send_response(cfd, buf, o)
56 sys_munmap(buf, MS_RESP_RESERVE)
57 return 0
58}
59// the page: template + head + body, spliced by the ONE renderer; -1 when the template is unreadable or the buffer would overflow
60func ms_render(out: *u8, cap: i64, head: *u8, body: *u8, bn: i64) -> i64 {
61 let lp: *i64 = sys_mmap(16) as *i64
62 let tmpl: *u8 = mo_read(MO_TMPL, lp)
63 if (tmpl as i64) == 0 { return 0 - 1 }
64 return mo_splice(out, cap, tmpl, lp[0], head, mo_slen(head), body, bn)
65}
66// the index page's bytes into out -- serve and emit both call THIS, so the fallback file cannot drift from the live page
67func ms_render_index(out: *u8, cap: i64) -> i64 {
68 let lc: *i64 = sys_mmap(16) as *i64
69 let ld: *i64 = sys_mmap(16) as *i64
70 let clips: *u8 = mo_read(MO_CLIPS_ROWS, lc)
71 let demos: *u8 = mo_read(MO_DEMOS_ROWS, ld)
72 let body: *u8 = sys_mmap(MO_PAGE_CAP)
73 let bn: i64 = mo_body_index(body, clips, lc[0], demos, ld[0])
74 let n: i64 = ms_render(out, cap, "" as *u8, body, bn)
75 sys_munmap(body, MO_PAGE_CAP)
76 return n
77}
78func ms_page(cfd: i64, head: *u8, body: *u8, bn: i64) -> i64 {
79 let out: *u8 = sys_mmap(MO_PAGE_CAP)
80 let n: i64 = ms_render(out, MO_PAGE_CAP, head, body, bn)
81 if n < 0 { ms_text(cfd, "500 Internal Server Error" as *u8, "the page renderer refused: template unreadable or buffer exhausted\n" as *u8) } else {
82 ms_send(cfd, "200 OK" as *u8, "text/html; charset=utf-8" as *u8, out, n)
83 }
84 sys_munmap(out, MO_PAGE_CAP)
85 return 0
86}
87func ms_index(cfd: i64) -> i64 {
88 let out: *u8 = sys_mmap(MO_PAGE_CAP)
89 let n: i64 = ms_render_index(out, MO_PAGE_CAP)
90 if n < 0 { ms_text(cfd, "500 Internal Server Error" as *u8, "the page renderer refused: template unreadable or buffer exhausted\n" as *u8) } else {
91 ms_send(cfd, "200 OK" as *u8, "text/html; charset=utf-8" as *u8, out, n)
92 }
93 sys_munmap(out, MO_PAGE_CAP)
94 return 0
95}
96func ms_jobdir(id: *u8) -> *u8 { return mo_join(MO_JOBS_DIR, id) }
97// the job page: RUNNING (with a refresh) until the job's done marker exists, then the rig, the clips and the verdict form
98func ms_job(cfd: i64, id: *u8) -> i64 {
99 if mo_digits_only(id) == 0 { return ms_text(cfd, "400 Bad Request" as *u8, "a job id is digits only\n" as *u8) }
100 let jobdir: *u8 = ms_jobdir(id)
101 let stpath: *u8 = mo_join(jobdir, "status" as *u8)
102 if mo_exists(stpath) == 0 { return ms_text(cfd, "404 Not Found" as *u8, "no such job\n" as *u8) }
103 let ls: *i64 = sys_mmap(16) as *i64
104 let lc: *i64 = sys_mmap(16) as *i64
105 let la: *i64 = sys_mmap(16) as *i64
106 let lv: *i64 = sys_mmap(16) as *i64
107 let st: *u8 = mo_read(stpath, ls)
108 let done: i64 = mo_exists(mo_join(jobdir, "done" as *u8))
109 let clips: *u8 = mo_read(MO_CLIPS_ROWS, lc)
110 let applied: *u8 = mo_read(mo_join(jobdir, "clips" as *u8), la)
111 let verdicts: *u8 = mo_read(MO_VERDICTS, lv)
112 let body: *u8 = sys_mmap(MO_PAGE_CAP)
113 let bn: i64 = mo_body_job(body, id, st, ls[0], done, clips, lc[0], applied, la[0], verdicts, lv[0])
114 var head: *u8 = "" as *u8
115 if done == 0 { head = MS_REFRESH_HEAD }
116 ms_page(cfd, head, body, bn)
117 sys_munmap(body, MO_PAGE_CAP)
118 return 0
119}
120// serve one artifact from a job directory (name allowlisted by shape and suffix) or from the demos directory
121func ms_ctype(name: *u8) -> *u8 {
122 let n: i64 = mo_slen(name)
123 if n > 4 { if mo_streq(((name as i64) + n - 4) as *u8, ".png" as *u8) == 1 { return "image/png" as *u8 } }
124 if n > 4 { if mo_streq(((name as i64) + n - 4) as *u8, ".glb" as *u8) == 1 { return "model/gltf-binary" as *u8 } }
125 if n > 4 { if mo_streq(((name as i64) + n - 4) as *u8, ".nxa" as *u8) == 1 { return "application/octet-stream" as *u8 } }
126 if n > 4 { if mo_streq(((name as i64) + n - 4) as *u8, ".txt" as *u8) == 1 { return "text/plain; charset=utf-8" as *u8 } }
127 return "" as *u8
128}
129func ms_file(cfd: i64, dir: *u8, name: *u8) -> i64 {
130 if mo_safe_name(name) == 0 { return ms_text(cfd, "400 Bad Request" as *u8, "artifact name refused by shape\n" as *u8) }
131 let ct: *u8 = ms_ctype(name)
132 if mo_slen(ct) == 0 { return ms_text(cfd, "404 Not Found" as *u8, "only png, glb, nxa and txt artifacts are served\n" as *u8) }
133 let lp: *i64 = sys_mmap(16) as *i64
134 let b: *u8 = mo_read(mo_join(dir, name), lp)
135 if (b as i64) == 0 { return ms_text(cfd, "404 Not Found" as *u8, "artifact absent (the job may still be running, or that stage refused)\n" as *u8) }
136 return ms_send(cfd, "200 OK" as *u8, ct, b, lp[0])
137}
138func ms_art(cfd: i64, path: *u8, plen: i64) -> i64 {
139 let id: *u8 = sys_mmap(MO_VAL_CAP)
140 let name: *u8 = sys_mmap(MO_VAL_CAP)
141 mo_prev_seg(path, plen, id, MO_VAL_CAP)
142 mo_last_seg(path, plen, name, MO_VAL_CAP)
143 if mo_digits_only(id) == 0 { return ms_text(cfd, "400 Bad Request" as *u8, "a job id is digits only\n" as *u8) }
144 return ms_file(cfd, ms_jobdir(id), name)
145}
146func ms_demo(cfd: i64, path: *u8, plen: i64) -> i64 {
147 let name: *u8 = sys_mmap(MO_VAL_CAP)
148 mo_last_seg(path, plen, name, MO_VAL_CAP)
149 return ms_file(cfd, MO_DEMOS_DIR, name)
150}
151// POST /upload: multipart -> typed by magic -> a job directory -> the job organ spawned detached -> 303 to the job page
152func ms_upload(cfd: i64, req: *u8, hend: i64, body: *u8, blen: i64) -> i64 {
153 let bnd: *u8 = sys_mmap(MO_VAL_CAP)
154 let bl: i64 = mo_boundary(req, hend, bnd, MO_VAL_CAP)
155 if bl < 1 { return ms_text(cfd, "400 Bad Request" as *u8, "no multipart boundary in the request\n" as *u8) }
156 let off: *i64 = sys_mmap(16) as *i64
157 let len: *i64 = sys_mmap(16) as *i64
158 let f: i64 = mo_part_find(body, blen, bnd, bl, "model" as *u8, off, len)
159 if f < 0 { return ms_text(cfd, "400 Bad Request" as *u8, "malformed multipart body: a part without its closing boundary is refused, never half-read\n" as *u8) }
160 if f == 0 { return ms_text(cfd, "400 Bad Request" as *u8, "no part named model in the upload\n" as *u8) }
161 if len[0] < 8 { return ms_text(cfd, "400 Bad Request" as *u8, "the model part is empty\n" as *u8) }
162 let data: *u8 = ((body as i64) + off[0]) as *u8
163 let kind: i64 = mo_kind_of(data, len[0])
164 if kind == MO_KIND_UNKNOWN { return ms_text(cfd, "415 Unsupported Media Type" as *u8, "unknown bytes: this door accepts GLB (binary glTF), binary FBX and NXA, typed by their first bytes\n" as *u8) }
165 if kind == MO_KIND_OBJ { return ms_text(cfd, "415 Unsupported Media Type" as *u8, "OBJ recognised and refused by name: no sovereign OBJ reader is composed on this door yet (motion.plan MO2)\n" as *u8) }
166 var cells: i64 = MS_CELLS_DEFAULT
167 let coff: *i64 = sys_mmap(16) as *i64
168 let clen: *i64 = sys_mmap(16) as *i64
169 if mo_part_find(body, blen, bnd, bl, "cells" as *u8, coff, clen) == 1 { cells = mo_atoi(((body as i64) + coff[0]) as *u8, clen[0]) }
170 if cells < MS_CELLS_MIN { cells = MS_CELLS_DEFAULT }
171 if cells > MS_CELLS_MAX { cells = MS_CELLS_DEFAULT }
172 // the job: digit-named by the clock in milliseconds, so two uploads in one second still differ
173 let id: *u8 = sys_mmap(32)
174 let il: i64 = mo_num(id, 0, sys_clock_now_us() / 1000)
175 id[il] = 0 as u8
176 let jobdir: *u8 = ms_jobdir(id)
177 sys_mkdir(MO_JOBS_DIR, 493)
178 if sys_mkdir(jobdir, 493) < 0 { return ms_text(cfd, "500 Internal Server Error" as *u8, "could not create the job directory\n" as *u8) }
179 let inname: *u8 = sys_mmap(32)
180 var io: i64 = mo_cat(inname, 0, "in." as *u8)
181 io = mo_cat(inname, io, mo_kind_name(kind))
182 inname[io] = 0 as u8
183 if mo_write_all(mo_join(jobdir, inname), data, len[0]) != len[0] { return ms_text(cfd, "500 Internal Server Error" as *u8, "could not store the upload\n" as *u8) }
184 let kb: *u8 = sys_mmap(32)
185 var ko: i64 = mo_cat(kb, 0, mo_kind_name(kind))
186 kb[ko] = 10 as u8
187 mo_write_all(mo_join(jobdir, "kind" as *u8), kb, ko + 1)
188 let sb: *u8 = sys_mmap(256)
189 var so: i64 = mo_cat(sb, 0, "stage=queued\nok=0\nkind=" as *u8)
190 so = mo_cat(sb, so, mo_kind_name(kind))
191 so = mo_cat(sb, so, "\ncells=" as *u8)
192 so = mo_num(sb, so, cells)
193 so = mo_cat(sb, so, "\nbytes_in=" as *u8)
194 so = mo_num(sb, so, len[0])
195 sb[so] = 10 as u8
196 mo_write_all(mo_join(jobdir, "status" as *u8), sb, so + 1)
197 let cellstr: *u8 = sys_mmap(32)
198 let cl: i64 = mo_num(cellstr, 0, cells)
199 cellstr[cl] = 0 as u8
200 let words: *i64 = sys_mmap(MO_ARGV_CAP * 8) as *i64
201 let vrig: *u8 = "rig" as *u8
202 words[0] = vrig as i64; words[1] = jobdir as i64; words[2] = cellstr as i64
203 if mo_run_detached(MS_RIG_ELF, words, 3, mo_join(jobdir, "spawn.log" as *u8)) < 0 { return ms_text(cfd, "503 Service Unavailable" as *u8, "could not spawn the rig job\n" as *u8) }
204 let loc: *u8 = sys_mmap(MO_VAL_CAP)
205 var lo: i64 = mo_cat(loc, 0, "/motion/job/" as *u8)
206 lo = mo_cat(loc, lo, id)
207 loc[lo] = 0 as u8
208 return ms_redirect(cfd, loc)
209}
210// GET /anim?job=<id>&clip=<key>: the clip row names the donor and pose; the job organ is spawned detached; 303 back
211func ms_anim(cfd: i64, path: *u8, plen: i64) -> i64 {
212 let id: *u8 = sys_mmap(MO_VAL_CAP)
213 let key: *u8 = sys_mmap(MO_VAL_CAP)
214 mo_qparam(path, plen, "job" as *u8, id, MO_VAL_CAP)
215 mo_qparam(path, plen, "clip" as *u8, key, MO_VAL_CAP)
216 if mo_digits_only(id) == 0 { return ms_text(cfd, "400 Bad Request" as *u8, "a job id is digits only\n" as *u8) }
217 if mo_safe_name(key) == 0 { return ms_text(cfd, "400 Bad Request" as *u8, "clip key refused by shape\n" as *u8) }
218 let jobdir: *u8 = ms_jobdir(id)
219 if mo_exists(mo_join(jobdir, "done" as *u8)) == 0 { return ms_text(cfd, "409 Conflict" as *u8, "the rig job has not finished; apply a clip once the job page reads DONE\n" as *u8) }
220 if mo_exists(mo_join(jobdir, "rig.nxa" as *u8)) == 0 { return ms_text(cfd, "409 Conflict" as *u8, "the job has no rig (it failed at a named stage); nothing to animate\n" as *u8) }
221 let lc: *i64 = sys_mmap(16) as *i64
222 let rows: *u8 = mo_read(MO_CLIPS_ROWS, lc)
223 if (rows as i64) == 0 { return ms_text(cfd, "503 Service Unavailable" as *u8, "the clip rows are unreadable\n" as *u8) }
224 let r: i64 = mo_row_find(rows, lc[0], key)
225 if r < 0 { return ms_text(cfd, "404 Not Found" as *u8, "no clip row with that key: a clip is a data row, and an absent row is refused by name\n" as *u8) }
226 let donor: *u8 = sys_mmap(MO_VAL_CAP)
227 let pose: *u8 = sys_mmap(MO_VAL_CAP)
228 mo_row_field(rows, lc[0], r, 1, donor, MO_VAL_CAP)
229 mo_row_field(rows, lc[0], r, 2, pose, MO_VAL_CAP)
230 if mo_exists(donor) == 0 { return ms_text(cfd, "409 Conflict" as *u8, "the clip's donor asset is ABSENT on this host; the row stays, the apply refuses\n" as *u8) }
231 let words: *i64 = sys_mmap(MO_ARGV_CAP * 8) as *i64
232 let vanim: *u8 = "anim" as *u8
233 words[0] = vanim as i64; words[1] = jobdir as i64; words[2] = donor as i64; words[3] = pose as i64; words[4] = key as i64
234 let lg: *u8 = sys_mmap(MO_VAL_CAP)
235 var lo: i64 = mo_cat(lg, 0, "spawn_anim_" as *u8)
236 lo = mo_cat(lg, lo, key)
237 lo = mo_cat(lg, lo, ".log" as *u8)
238 lg[lo] = 0 as u8
239 if mo_run_detached(MS_RIG_ELF, words, 5, mo_join(jobdir, lg)) < 0 { return ms_text(cfd, "503 Service Unavailable" as *u8, "could not spawn the anim job\n" as *u8) }
240 let loc: *u8 = sys_mmap(MO_VAL_CAP)
241 var o: i64 = mo_cat(loc, 0, "/motion/job/" as *u8)
242 o = mo_cat(loc, o, id)
243 loc[o] = 0 as u8
244 return ms_redirect(cfd, loc)
245}
246// POST /verdict: job, v (accept or reject), words -> one journal row here AND one row on the acceptance plane
247func ms_verdict(cfd: i64, body: *u8, blen: i64) -> i64 {
248 let id: *u8 = sys_mmap(MO_VAL_CAP)
249 let v: *u8 = sys_mmap(MO_VAL_CAP)
250 let words: *u8 = sys_mmap(MO_VAL_CAP)
251 mo_kv(body, blen, "job" as *u8, id, MO_VAL_CAP)
252 mo_kv(body, blen, "v" as *u8, v, MO_VAL_CAP)
253 let wl: i64 = mo_kv(body, blen, "words" as *u8, words, MO_VAL_CAP)
254 if mo_digits_only(id) == 0 { return ms_text(cfd, "400 Bad Request" as *u8, "a job id is digits only\n" as *u8) }
255 if mo_exists(mo_join(ms_jobdir(id), "status" as *u8)) == 0 { return ms_text(cfd, "404 Not Found" as *u8, "a verdict on an absent job is refused by name\n" as *u8) }
256 var verdict: *u8 = "" as *u8
257 if mo_streq(v, "accept" as *u8) == 1 { verdict = "ACCEPT" as *u8 }
258 if mo_streq(v, "reject" as *u8) == 1 { verdict = "REJECT" as *u8 }
259 if mo_slen(verdict) == 0 { return ms_text(cfd, "400 Bad Request" as *u8, "v must be accept or reject\n" as *u8) }
260 // the words are stored as given, minus the two bytes that would break a row (pipe and newline), bounded
261 var i: i64 = 0
262 var wn: i64 = wl
263 if wn < 0 { wn = 0 }
264 if wn > MS_WORDS_CAP { wn = MS_WORDS_CAP }
265 while i < wn { let c: i64 = words[i] as i64; if c == 124 { words[i] = 32 as u8 } if c == 10 { words[i] = 32 as u8 } if c == 13 { words[i] = 32 as u8 } i = i + 1 }
266 words[wn] = 0 as u8
267 let epoch: i64 = sys_clock_now_us() / 1000000
268 let row: *u8 = sys_mmap(MO_VAL_CAP * 2)
269 var o: i64 = mo_cat(row, 0, id)
270 row[o] = 124 as u8; o = mo_cat(row, o + 1, verdict)
271 row[o] = 124 as u8; o = mo_num(row, o + 1, epoch)
272 row[o] = 124 as u8; o = mo_catb(row, o + 1, words, wn)
273 row[o] = 10 as u8; o = o + 1
274 mo_append(MO_VERDICTS, row, o)
275 // the acceptance plane: put <actor> <id> <title> <sev> <status> <owner> <scope> <note> -- the estate's own store verb
276 let subject: *u8 = sys_mmap(MO_VAL_CAP)
277 var so: i64 = mo_cat(subject, 0, "motion-job-" as *u8); so = mo_cat(subject, so, id); subject[so] = 0 as u8
278 let target: *u8 = sys_mmap(MO_VAL_CAP)
279 var to: i64 = mo_cat(target, 0, "/motion/job/" as *u8); to = mo_cat(target, to, id); target[to] = 0 as u8
280 let aw: *i64 = sys_mmap(MO_ARGV_CAP * 8) as *i64
281 let vput: *u8 = "put" as *u8
282 let voper: *u8 = "operator" as *u8
283 let vsev: *u8 = "0" as *u8
284 aw[0] = MS_ACCEPT_PLANE as i64; aw[1] = vput as i64; aw[2] = voper as i64; aw[3] = id as i64; aw[4] = subject as i64; aw[5] = vsev as i64; aw[6] = verdict as i64; aw[7] = voper as i64; aw[8] = target as i64; aw[9] = words as i64
285 mo_run_detached(MS_STORE_ELF, aw, 10, mo_join(ms_jobdir(id), "verdict_put.log" as *u8))
286 let loc: *u8 = sys_mmap(MO_VAL_CAP)
287 var lo: i64 = mo_cat(loc, 0, "/motion/job/" as *u8)
288 lo = mo_cat(loc, lo, id)
289 loc[lo] = 0 as u8
290 return ms_redirect(cfd, loc)
291}
292func ms_emit(outpath: *u8) -> i64 {
293 let out: *u8 = sys_mmap(MO_PAGE_CAP)
294 let n: i64 = ms_render_index(out, MO_PAGE_CAP)
295 if n < 0 { msw("MOTION-EMIT REFUSED: template unreadable or buffer exhausted\n" as *u8); return 1 }
296 let w: i64 = mo_write_all(outpath, out, n)
297 if w != n { msw("MOTION-EMIT REFUSED: write failed\n" as *u8); return 1 }
298 msw("MOTION-EMIT OK bytes=" as *u8)
299 let nb: *u8 = sys_mmap(64)
300 var no: i64 = mo_num(nb, 0, n); no = mo_cat(nb, no, " path=" as *u8); no = mo_cat(nb, no, outpath); no = mo_cat(nb, no, "\n" as *u8)
301 sys_write(1, nb, no)
302 return 0
303}
304func main(argc: i64, argv: *i64) -> i64 {
305 var port: i64 = MS_PORT_DEFAULT
306 if argc >= 2 {
307 let a: *u8 = argv[1] as *u8
308 if mo_streq(a, "emit" as *u8) == 1 {
309 if argc < 3 { msw("usage: nx_motion_serve [port] | emit <out.html>\n" as *u8); return MS_EXIT_USAGE }
310 return ms_emit(argv[2] as *u8)
311 }
312 let v: i64 = mo_atoi(a, mo_slen(a))
313 if v > 0 { port = v }
314 }
315 let addr: *u8 = sys_mmap(64)
316 nx_http_server_addr_loopback(addr, port)
317 let vd: *i64 = (sys_mmap(8)) as *i64
318 let lfd: i64 = nx_http_server_listen(addr, MS_BACKLOG, vd)
319 if lfd < 0 {
320 sys_write(2, "[nx_motion_serve] LISTEN-FAILED verdict=" as *u8, 40)
321 sys_write(2, nxs_verdict_name(vd[0]), mo_slen(nxs_verdict_name(vd[0])))
322 sys_write(2, "\n" as *u8, 1)
323 sys_exit(1)
324 return 1
325 }
326 msw("[nx_motion_serve] listening on loopback\n" as *u8)
327 let req: *u8 = sys_mmap(MO_REQ_CAP)
328 let mth: *i64 = (sys_mmap(8)) as *i64
329 let poff: *i64 = (sys_mmap(8)) as *i64
330 let plen: *i64 = (sys_mmap(8)) as *i64
331 let clen: *i64 = (sys_mmap(8)) as *i64
332 let boff: *i64 = (sys_mmap(8)) as *i64
333 let rn: *i64 = (sys_mmap(8)) as *i64
334 var alive: i64 = 1
335 while alive == 1 {
336 let cfd: i64 = nx_http_server_accept_one(lfd, vd)
337 if cfd >= 0 {
338 let rr: i64 = nx_http_server_read_request(cfd, req, MO_REQ_CAP, mth, poff, plen, clen, boff, rn)
339 let path: *u8 = ((req as i64) + poff[0]) as *u8
340 if rr != NXS_OK {
341 if clen[0] > MO_UPLOAD_CAP { ms_text(cfd, "413 Content Too Large" as *u8, "the direct door takes a body up to the named cap printed on the page; larger models belong to the chunked door (motion.plan MO13)\n" as *u8) } else {
342 ms_text(cfd, "400 Bad Request" as *u8, "the request did not parse as HTTP/1.1, or its body ended early\n" as *u8)
343 }
344 } else {
345 var blen: i64 = clen[0]
346 if rn[0] - boff[0] < blen { blen = rn[0] - boff[0] }
347 if blen < 0 { blen = 0 }
348 let body: *u8 = ((req as i64) + boff[0]) as *u8
349 if mth[0] == MS_METHOD_GET {
350 if mo_path_has(path, plen[0], "/art/" as *u8) == 1 { ms_art(cfd, path, plen[0]) } else {
351 if mo_path_has(path, plen[0], "/demo/" as *u8) == 1 { ms_demo(cfd, path, plen[0]) } else {
352 if mo_path_has(path, plen[0], "/job/" as *u8) == 1 { let id: *u8 = sys_mmap(MO_VAL_CAP); mo_last_seg(path, plen[0], id, MO_VAL_CAP); ms_job(cfd, id) } else {
353 if mo_path_has(path, plen[0], "/anim" as *u8) == 1 { ms_anim(cfd, path, plen[0]) } else {
354 ms_index(cfd)
355 } } } }
356 } else {
357 if mth[0] == MS_METHOD_POST {
358 if mo_path_has(path, plen[0], "/upload" as *u8) == 1 { ms_upload(cfd, req, boff[0], body, blen) } else {
359 if mo_path_has(path, plen[0], "/verdict" as *u8) == 1 { ms_verdict(cfd, body, blen) } else {
360 ms_text(cfd, "404 Not Found" as *u8, "POST routes: /motion/upload and /motion/verdict\n" as *u8)
361 } }
362 } else {
363 ms_text(cfd, "405 Method Not Allowed" as *u8, "GET and POST only\n" as *u8)
364 } }
365 }
366 }
367 }
368 sys_exit(0)
369 return 0
370}