nx_game_asset_prepare_t132.nx source
↩ module page · 15 lines · 7465 B
1// Emits the browser orchestration boundary; binding mathematics stays in native Wasm.
2func gpe_garment_prepare(out: *u8,pos: i64) -> i64 {
3 let len: *i64=sys_mmap(16) as *i64
4 let config: *u8=sys_read_file("buildroot/knowledge/garment_binding_t132.conf" as *u8,len)
5 if len[0]<=0 { rk_err("garment preparation config missing\n" as *u8);return 0 }
6 var p: i64=gpe_ap(out,pos,"const NX_GARMENT_BIND_CONFIG=" as *u8)
7 p=rk_js_str(out,p,config,len[0])
8 p=gpe_ap(out,p,";\nconst NX_GARMENT_BIND_WORKER=" as *u8)
9 let worker: *u8="onmessage=async e=>{try{\nconst {asset,count,policy,module_url,operation}=e.data;\nif(operation!=='legacy'&&operation!=='attachment-v1')throw Error('operation-refused');\nconst r=await fetch(module_url);if(!r.ok)throw Error('module-http-'+r.status);\nconst reader=r.body.getReader(),parts=[];let size=0;\ntry{for(;;){const x=await reader.read();if(x.done)break;size+=x.value.length;if(size>policy.module_bytes)throw Error('module-extent');parts.push(x.value);}}finally{await reader.cancel();}\nif(size!==policy.module_bytes)throw Error('module-extent');\nconst bytes=new Uint8Array(size);let at=0;for(const x of parts){bytes.set(x,at);at+=x.length;}\nconst digest=Array.from(new Uint8Array(await crypto.subtle.digest('SHA-256',bytes)),x=>x.toString(16).padStart(2,'0')).join('');\nif(digest!==policy.module_sha256)throw Error('module-identity');\nconst module=await WebAssembly.compile(bytes);\nif(WebAssembly.Module.imports(module).length)throw Error('module-host-imports');\nconst i=await WebAssembly.instantiate(module,{}),ex=i.exports;\nconst start=ex.memory.buffer.byteLength,page=65536,work=start+Math.ceil(asset.byteLength/8)*8;\nconst grow=end=>{if(!Number.isSafeInteger(end)||Math.ceil(end/page)*page>policy.linear_memory_budget_bytes)throw Error('linear-memory-budget');const current=ex.memory.buffer.byteLength;if(end>current)ex.memory.grow(Math.ceil((end-current)/page));};\ngrow(work+112);new Uint8Array(ex.memory.buffer,start,asset.byteLength).set(new Uint8Array(asset));\nconst began=performance.now();let out=work+112,need=count*8,rc;\nif(operation==='attachment-v1'){\n if(typeof ex.ngb_attachment_bytes_v1!=='function'||typeof ex.ngb_attachment_pack_v1!=='function')throw Error('module-attachment-export');\n const measured=ex.ngb_attachment_bytes_v1(BigInt(start),BigInt(asset.byteLength),BigInt(work),112n);\n if(measured<=0n||measured>BigInt(policy.linear_memory_budget_bytes))throw Error('native-attachment-measure-'+measured);\n need=Number(measured);grow(out+need);\n rc=ex.ngb_attachment_pack_v1(BigInt(start),BigInt(asset.byteLength),BigInt(out),BigInt(need),BigInt(work),112n);\n}else{\n if(typeof ex.ngb_map!=='function')throw Error('module-binding-export');grow(out+need);\n rc=ex.ngb_map(BigInt(start),BigInt(asset.byteLength),BigInt(out),BigInt(need),BigInt(policy.step),BigInt(policy.lower_band));\n}\nif(rc!==BigInt(need))throw Error('native-preparation-'+String(rc));\nconst result=ex.memory.buffer.slice(out,out+need);\npostMessage({state:'prepared',result,compute_ms:performance.now()-began,linear_memory_bytes:ex.memory.buffer.byteLength},[result]);\n}catch(error){postMessage({state:'failed',error:String(error)});}};" as *u8
10 p=rk_js_str(out,p,worker,gpe_slen(worker))
11 p=gpe_ap(out,p,";\n" as *u8)
12 p=gpe_ap(out,p,"const NX_GARMENT_BIND_POLICY=JSON.parse(NX_GARMENT_BIND_CONFIG);\n(function(p){if(!p||p.version!==1||!/^\\/releases\\/[a-zA-Z0-9_-]+\\.wasm$/.test(p.module_url)||!/^[0-9a-f]{64}$/.test(p.module_sha256))throw Error('garment-preparation-config-identity');for(const k of ['module_bytes','linear_memory_budget_bytes','asset_budget_bytes','deadline_ms','step'])if(!Number.isSafeInteger(p[k])||p[k]<=0)throw Error('garment-preparation-config-'+k);if(!Number.isSafeInteger(p.lower_band)||p.lower_band<0)throw Error('garment-preparation-config-band');})(NX_GARMENT_BIND_POLICY);\nconst nxGarmentActivity=window.__nx_garment_activity={attempts:0,active_workers:0,peak_workers:0,cancelled:0};\nasync function nxPrepareGarmentBinding(asset,count){return nxPrepareGarmentOperation(asset,count,'legacy');}\nasync function nxPrepareGarmentAttachment(asset){return nxPrepareGarmentOperation(asset,0,'attachment-v1');}\nasync function nxPrepareGarmentOperation(asset,count,operation){for(;;){if(typeof nxDemand!=='undefined'&&!nxDemand.active)await new Promise(resolve=>nxDemand.idle(resolve));try{return await nxPrepareGarmentAttempt(asset,count,operation);}catch(error){if(!error||error.message!=='garment-preparation-page-hidden'||typeof nxDemand==='undefined')throw error;await new Promise(resolve=>nxDemand.idle(resolve));}}}\nasync function nxPrepareGarmentAttempt(asset,count,operation){\nconst policy=NX_GARMENT_BIND_POLICY;\nconst report={state:'preparing',module_url:policy.module_url,module_sha256:policy.module_sha256,asset_bytes:asset instanceof ArrayBuffer?asset.byteLength:null,count,operation,policy,started_at:new Date().toISOString(),scope:'Native garment binding or attachment packing in isolated worker; not full character preparation'};\nwindow.__nx_garment_prepare=report;\nlet worker,url,timer,onHide,offDemand;const started=performance.now();nxGarmentActivity.attempts++;\ntry{\nif(!(asset instanceof ArrayBuffer)||asset.byteLength>policy.asset_budget_bytes||!Number.isSafeInteger(count)||count<0||count>Math.floor(policy.linear_memory_budget_bytes/8))throw Error('garment-preparation-input-budget');\nurl=URL.createObjectURL(new Blob([NX_GARMENT_BIND_WORKER],{type:'text/javascript'}));worker=new Worker(url);nxGarmentActivity.active_workers++;nxGarmentActivity.peak_workers=Math.max(nxGarmentActivity.peak_workers,nxGarmentActivity.active_workers);\nconst reply=await new Promise((resolve,reject)=>{\ntimer=setTimeout(()=>reject(Error('garment-preparation-deadline')),policy.deadline_ms);\nonHide=()=>reject(Error('garment-preparation-page-hidden'));addEventListener('pagehide',onHide,{once:true});if(typeof nxDemand!=='undefined')offDemand=nxDemand.onChange(active=>{if(!active)onHide();});\nworker.onmessage=e=>e.data&&e.data.state==='prepared'?resolve(e.data):reject(Error(e.data&&e.data.error||'garment-preparation-worker-response'));\nworker.onerror=e=>reject(Error(e.message||'garment-preparation-worker-error'));\nworker.onmessageerror=()=>reject(Error('garment-preparation-message-decode'));\nconst input=asset.slice(0);worker.postMessage({asset:input,count,operation,policy,module_url:new URL(policy.module_url,location.href).href},[input]);\n});\nif(!(reply.result instanceof ArrayBuffer)||(operation==='legacy'?reply.result.byteLength!==count*8:reply.result.byteLength<64||reply.result.byteLength>policy.linear_memory_budget_bytes))throw Error('garment-preparation-result-extent');\nreport.state='prepared';report.compute_ms=reply.compute_ms;report.linear_memory_bytes=reply.linear_memory_bytes;\nreturn operation==='legacy'?new BigInt64Array(reply.result):reply.result;\n}catch(error){const paused=error&&error.message==='garment-preparation-page-hidden';report.state=paused?'paused':'failed';report.error=String(error);if(paused)nxGarmentActivity.cancelled++;throw error;}\nfinally{clearTimeout(timer);if(onHide)removeEventListener('pagehide',onHide);if(offDemand)offDemand();if(worker){worker.terminate();nxGarmentActivity.active_workers--;}if(url)URL.revokeObjectURL(url);report.elapsed_ms=performance.now()-started;report.cleanup='closed';}\n}\n" as *u8)
13 sys_munmap(config,len[0]+1);sys_munmap(len as *u8,16)
14 return p
15}