code wiki / _hdl_build / nx_torrent_shell.nx
nx_torrent_shell.nx
buildroot/runtime/_hdl_build/nx_torrent_shell.nx
about
nx_torrent_shell.nx -- R4a: the Nishi-EMITTED /torrent frontend (the gs_shell pattern -- a Nishi organ emits
the markup + the irreducible last-mile fetch bindings; NOT hand-authored JS product logic, per the JS-revert
lesson). It is the operator's torrent MANAGER served behind the front gateway at nishifamily.com/torrent:
- add row: magnet input + a DESTINATION selector (media=SFW / gallery=NSFW) + Add -> POST /torrent/api/add
body "magnet=..&area=media|gallery". The SERVER enforces (a family viewer's area=gallery is denied);
the selector just expresses intent.
- status poll GET /torrent/api/status -> render each download (name / % / peers / state) + a Watch button.
- Watch -> <video src=/torrent/stream/<id>> (the daemon's Range/206 stream-while-downloading path).
ts_emit(out) writes the page into out (returns len) so the gateway can serve it; main writes it to stdout
(the gate captures + checks the required elements). license_tier: ORIGINAL
dependencies 1 imports · 1 importers
imports: nx_syscalls.nx
imported by: nx_torrent_shell_gate.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 12 | const TS_MAGIC_65536: i64 = 65536 |
| 14 | const TS_HTML: *u8 = "<!doctype html><html><head><meta charset=utf-8><meta name=viewport content=\"width=device-width,initial-scale=1\"><title>Nishi Torrent</title><style>body{font-family:system-ui,sans-serif;max-width:860px;margin:4vh auto;padding:0 16px;color:#cdd7e6;background:#0b1019}h1{font-size:1.25rem;color:#e8eef7}.row{display:flex;gap:8px;flex-wrap:wrap;margin:12px 0}input,select{padding:9px;border:1px solid #2a3550;border-radius:5px;background:#121a28;color:#e8eef7}input#mag{flex:1;min-width:220px}button{padding:9px 16px;background:#2d6cdf;color:#fff;border:0;border-radius:5px;cursor:pointer}#msg{min-height:1.2em;color:#7c8aa5;font-size:.85rem;margin:6px 0}.it{padding:10px;margin:7px 0;background:#121a28;border-left:3px solid #2d6cdf;border-radius:4px}.bar{height:6px;background:#1c2740;border-radius:3px;overflow:hidden;margin:6px 0}.fill{height:6px;background:#2d6cdf}.meta{font-size:.8rem;color:#7c8aa5}video{width:100%;margin-top:10px;background:#000;border-radius:6px;display:none}</style></head><body><h1>Nishi Torrent</h1><div class=row><input id=mag placeholder=\"magnet:?xt=urn:btih:...\"><select id=area title=\"download destination\"><option value=media>Media (SFW)</option><option value=gallery>Gallery (NSFW)</option></select><button onclick=add()>Add</button></div><div id=msg></div><div id=list></div><video id=pl controls></video><script>function $(i){return document.getElementById(i)}function M(t){$('msg').textContent=t}async function add(){var m=$('mag').value.trim();if(!m){M('paste a magnet');return}M('adding...');try{var r=await fetch('/torrent/api/add',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'magnet='+encodeURIComponent(m)+'&area='+encodeURIComponent($('area').value)});if(r.status===403){M('not allowed: that area is operator-only');return}var ct=(r.headers.get('content-type')||'');if(ct.indexOf('json')<0){M('Preview only \\u2014 the torrent backend is not live on the hub yet.');return}var j=await r.json();M(j.id?('added '+j.id):(j.error||'error'));$('mag').value=''}catch(e){M('Preview only \\u2014 backend not live yet.')}}function watch(id){var v=$('pl');v.style.display='block';v.src='/torrent/stream/'+encodeURIComponent(id);v.play()}function pct(d){return d.totalPieces>0?Math.floor(d.havePieces*100/d.totalPieces):0}async function refresh(){try{var r=await fetch('/torrent/api/status');var ct=(r.headers.get('content-type')||'');if(ct.indexOf('json')<0){M('Preview \\u2014 backend not live on the hub yet; this is the frontend only.');return}var j=await r.json();var L=$('list');L.innerHTML='';(j.downloads||[]).forEach(function(d){var p=pct(d);var el=document.createElement('div');el.className='it';el.innerHTML='<b>'+(d.name||d.id)+'</b> — '+d.status+'<div class=bar><div class=fill style=\"width:'+p+'%\"></div></div><div class=meta>'+p+'% · '+(d.peers||0)+' peers · '+Math.floor((d.done||0)/1048576)+' MB</div>';var b=document.createElement('button');b.textContent='\\u25b6 Watch';b.onclick=function(){watch(d.id)};el.appendChild(b);L.appendChild(el)})}catch(e){}}refresh();setInterval(refresh,2000);</script></body></html>" as *u8 |
functions
| 16 | func ts_len(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } |
| 20 | func ts_emit(out: *u8) -> i64 |
| 28 | func main() -> i64 |