Files
juzi/h5/test/private-case-preview.mjs
2026-10-15 22:16:01 +08:00

37 lines
3.1 KiB
JavaScript

// Loopback-only, read-only preview. Private downloaded files stay outside Git.
// H5_PRIVATE_CASE_DIR=/private/case node h5/test/private-case-preview.mjs
import http from 'node:http';import fs from 'node:fs';import path from 'node:path';
import{fileURLToPath}from'node:url';
const dir=process.env.H5_PRIVATE_CASE_DIR;
if(!dir)throw Error('Set H5_PRIVATE_CASE_DIR to the explicitly downloaded private case');
const root=fileURLToPath(new URL('../',import.meta.url));
const raw=JSON.parse(fs.readFileSync(path.join(dir,'raw.json')));
const photos=['front','left','right'].map(k=>'data:image/jpeg;base64,'+fs.readFileSync(path.join(dir,k+'.jpg')).toString('base64'));
const fixture={result:raw.result,side:{left:raw.left_side_result,right:raw.right_side_result},face_rectangle:raw.face_rectangle,photos,
realAge:Number(process.env.H5_CASE_REAL_AGE||26),skinType:process.env.H5_CASE_SKIN_TYPE||'干性肌肤'};
fixture.wrinkle_views={version:'independent-side-wrinkles-v1'};
for(const view of ['left','right']){
try{const data=JSON.parse(fs.readFileSync(path.join(dir,view+'-wrinkles.json')));fixture.wrinkle_views[view]={status:'ready',result:data.result,face_rectangle:data.face_rectangle};}catch{}
}
const mime={'.html':'text/html; charset=utf-8','.js':'application/javascript; charset=utf-8','.css':'text/css; charset=utf-8','.json':'application/json','.png':'image/png','.jpg':'image/jpeg','.svg':'image/svg+xml','.woff2':'font/woff2','.webp':'image/webp','.mp3':'audio/mpeg'};
const server=http.createServer((req,res)=>{
res.setHeader('Cache-Control','no-store');res.setHeader('X-Robots-Tag','noindex, nofollow');
if(req.method!=='GET'){res.writeHead(405);return res.end();}
let pathname;try{pathname=decodeURIComponent(new URL(req.url,'http://localhost').pathname);}catch{res.writeHead(400);return res.end();}
if(pathname==='/api/auth/session'||pathname==='/api/auth/config'){
res.setHeader('Content-Type','application/json');return res.end(JSON.stringify({ok:true,wechat:false,user:{id:'private-case-preview',kind:'browser'}}));
}
if(pathname==='/assets/mock/report-fixture.js'){
res.setHeader('Content-Type',mime['.js']);return res.end('window.MOCK_FIXTURE='+JSON.stringify(fixture)+';');
}
const file=path.resolve(root,'.'+(pathname==='/'?'/index.html':pathname));
if(!file.startsWith(root)||/^\/(data|api|test|lib)(\/|$)/.test(pathname)||pathname==='/server.js'||pathname.split('/').some(s=>s.startsWith('.'))){res.writeHead(404);return res.end();}
const type=mime[path.extname(file)];if(!type){res.writeHead(404);return res.end();}
try{
let data=fs.readFileSync(file);
if(pathname==='/js/app.js')data=data.toString().replace("realAge: +($('#f-age').value || 0) || 28",'realAge: window.MOCK_FIXTURE.realAge').replace("skinType: SKINS[skinIndex].name\n }), fx ?",'skinType: window.MOCK_FIXTURE.skinType\n }), fx ?');
res.setHeader('Content-Type',type);res.end(data);
}catch{res.writeHead(404);res.end();}
});
server.listen(Number(process.env.PORT||18125),'127.0.0.1',()=>console.log('Private case preview ready on loopback port '+server.address().port+'; GET only; no upstream calls or writes'));