code wiki / _hdl_build / nx_translate_daemon.nx
nx_translate_daemon.nx source
↩ module page · 159 lines · 6558 B
1// nx_translate_daemon.nx -- the SOVEREIGN live /translate service for nishifamily.com/video, now on the
2// DATA-DRIVEN RU<->EN engine (nx_xlate_mt) -- replaces the old toy EN->ES (sea/tea/go) demo. Loopback :8447,
3// plain HTTP behind the edge; supervised by the existing hostctl guard (nx_hostctl.nx HC_XLATE :8447) so it
4// CANNOT affect the video/signaling path. GET /translate?text=<urlenc>[&dir=ru2en|en2ru] -> text/plain
5// (CORS-open). Direction auto-detected from Cyrillic when dir= absent. Lexicon + morphology load from
6// knowledge/xlate/ at startup. Any non-text GET (e.g. a health probe) -> 200 "?" so the guard sees it alive.
7// genealogy_id: sovereign_data_driven_ruen_mt_v1 license_tier: ORIGINAL
8import "nx_http_server.nx"
9import "nx_xlate_mt.nx"
10import "nx_syscalls.nx"
11const TD_MAGIC_8192: i64 = 8192
12const TD_MAGIC_4096: i64 = 4096
13const TD_MAGIC_16384: i64 = 16384
14
15const TD_PORT: i64 = 8447
16const TD_HDR1: *u8 = "HTTP/1.1 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: " as *u8
17const TD_HDR2: *u8 = "\r\nConnection: close\r\n\r\n" as *u8
18
19func td_puts(buf: *u8, off: i64, s: *u8) -> i64 {
20 var o: i64 = off
21 var i: i64 = 0
22 while s[i] != (0 as u8) { buf[o] = s[i]; o = o + 1; i = i + 1 }
23 return o
24}
25func td_wdec(buf: *u8, off: i64, v: i64) -> i64 {
26 var o: i64 = off
27 var m: i64 = v
28 if m == 0 { buf[o] = 48; return o + 1 }
29 let t: *u8 = sys_mmap(28)
30 var k: i64 = 0
31 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
32 while k > 0 { buf[o] = t[k - 1]; o = o + 1; k = k - 1 }
33 sys_munmap(t, 28)
34 return o
35}
36func td_hex(c: i64) -> i64 {
37 if c >= 48 { if c <= 57 { return c - 48 } }
38 if c >= 97 { if c <= 102 { return c - 87 } }
39 if c >= 65 { if c <= 70 { return c - 55 } }
40 return 0 - 1
41}
42// find "text=" in req[0..len), URL-decode value (until '&'/space/CR/LF/end) into out; return length
43func td_param(req: *u8, len: i64, out: *u8) -> i64 {
44 var i: i64 = 0
45 var start: i64 = 0 - 1
46 while i + 5 <= len {
47 var m: i64 = 1
48 if (req[i] as i64) != 116 { m = 0 }
49 if (req[i+1] as i64) != 101 { m = 0 }
50 if (req[i+2] as i64) != 120 { m = 0 }
51 if (req[i+3] as i64) != 116 { m = 0 }
52 if (req[i+4] as i64) != 61 { m = 0 }
53 if m == 1 { start = i + 5; break }
54 i = i + 1
55 }
56 if start < 0 { return 0 }
57 var o: i64 = 0
58 var j: i64 = start
59 while j < len {
60 let c: i64 = req[j] as i64
61 if c == 38 { break }
62 if c == 32 { break }
63 if c == 13 { break }
64 if c == 10 { break }
65 if c == 37 {
66 if j + 2 < len {
67 let h: i64 = td_hex(req[j+1] as i64)
68 let l: i64 = td_hex(req[j+2] as i64)
69 if h >= 0 { if l >= 0 { out[o] = ((h * 16) + l) as u8; o = o + 1; j = j + 3 } }
70 if h < 0 { out[o] = c as u8; o = o + 1; j = j + 1 }
71 if h >= 0 { if l < 0 { out[o] = c as u8; o = o + 1; j = j + 1 } }
72 } else { out[o] = c as u8; o = o + 1; j = j + 1 }
73 } else {
74 if c == 43 { out[o] = 32 as u8; o = o + 1; j = j + 1 } else { out[o] = c as u8; o = o + 1; j = j + 1 }
75 }
76 }
77 return o
78}
79func td_dirparam(req: *u8, len: i64) -> i64 {
80 var i: i64 = 0
81 while i + 3 <= len {
82 if (req[i] as i64) == 50 {
83 if (req[i+1] as i64) == 114 { if (req[i+2] as i64) == 117 { return 1 } }
84 if (req[i+1] as i64) == 101 { if (req[i+2] as i64) == 110 { return 2 } }
85 }
86 i = i + 1
87 }
88 return 0
89}
90func td_autodir(txt: *u8, n: i64) -> i64 {
91 var i: i64 = 0
92 while i < n { if (txt[i] as i64) >= 208 { return 1 } i = i + 1 }
93 return 0
94}
95func main() -> i64 {
96 let lnp: *i64 = sys_mmap(8) as *i64
97 let mnp: *i64 = sys_mmap(8) as *i64
98 let lex: *u8 = sys_read_file("buildroot/runtime/_hdl_build/xlate_lex.tsv" as *u8, lnp)
99 let morph: *u8 = sys_read_file("buildroot/runtime/_hdl_build/xlate_morph_ru.tsv" as *u8, mnp)
100 if (lex as i64) == 0 { return 2 }
101 var morphn: i64 = 0
102 if (morph as i64) != 0 { morphn = mnp[0] }
103 let eng: *i64 = sys_mmap(256) as *i64
104 xl_build(eng, lex, lnp[0], morph, morphn)
105 let addr: *u8 = sys_mmap(16)
106 nx_http_server_addr_loopback(addr, TD_PORT)
107 let lv: *i64 = sys_mmap(8) as *i64
108 let listen_fd: i64 = nx_http_server_listen(addr, 16, lv)
109 if listen_fd < 0 { return 1 }
110 let banner: *u8 = "nx_translate_daemon: sovereign data-driven RU<->EN /translate on 127.0.0.1:8447\n" as *u8
111 var bn: i64 = 0
112 while banner[bn] != (0 as u8) { bn = bn + 1 }
113 sys_write(1, banner, bn)
114 let req: *u8 = sys_mmap(TD_MAGIC_8192)
115 let mo: *i64 = sys_mmap(8) as *i64
116 let po: *i64 = sys_mmap(8) as *i64
117 let pl: *i64 = sys_mmap(8) as *i64
118 let cl: *i64 = sys_mmap(8) as *i64
119 let bo: *i64 = sys_mmap(8) as *i64
120 let rn: *i64 = sys_mmap(8) as *i64
121 let cv: *i64 = sys_mmap(8) as *i64
122 let txt: *u8 = sys_mmap(TD_MAGIC_4096)
123 let out: *u8 = sys_mmap(TD_MAGIC_8192)
124 let resp: *u8 = sys_mmap(TD_MAGIC_16384)
125 var run: i64 = 1
126 while run == 1 {
127 let cfd: i64 = nx_http_server_accept_one(listen_fd, cv)
128 if cfd >= 0 {
129 let rc: i64 = nx_http_server_read_request(cfd, req, TD_MAGIC_8192, mo, po, pl, cl, bo, rn)
130 if rc == NXS_OK {
131 let tlen: i64 = td_param(req, rn[0], txt)
132 if tlen > 0 {
133 var dir: i64 = td_autodir(txt, tlen)
134 let dp: i64 = td_dirparam(req, rn[0])
135 if dp == 1 { dir = 0 }
136 if dp == 2 { dir = 1 }
137 let olen: i64 = xl_translate(eng, txt, tlen, dir, out, TD_MAGIC_8192)
138 var o: i64 = 0
139 o = td_puts(resp, o, TD_HDR1)
140 o = td_wdec(resp, o, olen)
141 o = td_puts(resp, o, TD_HDR2)
142 var i: i64 = 0
143 while i < olen { resp[o + i] = out[i]; i = i + 1 }
144 o = o + olen
145 nx_http_server_send_response(cfd, resp, o)
146 } else {
147 var o2: i64 = 0
148 o2 = td_puts(resp, o2, TD_HDR1)
149 o2 = td_wdec(resp, o2, 1)
150 o2 = td_puts(resp, o2, TD_HDR2)
151 resp[o2] = 63 as u8
152 o2 = o2 + 1
153 nx_http_server_send_response(cfd, resp, o2)
154 }
155 } else { sys_close(cfd) }
156 }
157 }
158 return 0
159}