| 1234567891011121314151617181920212223242526272829303132333435 |
- // Restricted temporary read gateways. No business writes; delete on completion.
- import fs from 'node:fs';
- import {randomBytes,createHash} from 'node:crypto';
- import {browserHarness} from './browser-case.mjs';
- import {patchAdminSpeed} from '../../scripts/admin-speed-patch.mjs';
- const env={};for(const line of fs.readFileSync('/Users/mac/.config/xiaoshu/legacy-sync-nightly.env','utf8').split('\n')){const m=line.match(/^(?:export\s+)?(XIAOSHU_[A-Z0-9_]+)=(.*)$/);if(m)env[m[1]]=m[2].replace(/^['"]|['"]$/g,'');}
- const token=env.XIAOSHU_SYNC_OPERATOR_TOKEN,app=env.XIAOSHU_PARSE_APP_ID,master=process.env.XIAOSHU_MASTER_KEY,base='https://server.xiaoshu.pro';
- if(!master||!app||!token)throw Error('Missing authorized performance configuration');
- const out='tmp/admin-speed-2026-11-10';fs.mkdirSync(out,{recursive:true,mode:0o700});
- async function parse(path,method='GET',body){const r=await fetch(base+'/parse'+path,{method,headers:{'Content-Type':'application/json','X-Parse-Application-Id':app,'X-Parse-Master-Key':master},body:body?JSON.stringify(body):undefined});if(!r.ok)throw Error('Parse HTTP '+r.status);return r.json();}
- const me=await(await fetch(base+'/parse/users/me',{headers:{'X-Parse-Application-Id':app,'X-Parse-Session-Token':token}})).json();if(!me.objectId)throw Error('Invalid operator');
- const original=JSON.parse(fs.readFileSync(out+'/online-before.json')).code;
- const survey=JSON.parse(fs.readFileSync('tmp/admin-data-2026-10-15/survey.json')).results;
- const cases=survey.map(row=>({page:row.path,params:{...row.first.requests[0].params,...(row.path==='coaches'?{refresh:true}:{})}})).filter(row=>!process.env.PERF_PAGES||process.env.PERF_PAGES.split(',').includes(row.page));
- const allowed=[...new Set([...cases.map(c=>c.params.operation),'ops/vocabulary/list','ops/special-training/list'])],functions=[],results=[];let browser;
- function clean(value){if(value==='工作台仅展示实时预估金额;结算前须在工资模块核验来源')return '金额已按实时完课记录计算,结算资格仍需完整核验';if(Array.isArray(value))return value.map(clean);if(value&&typeof value==='object')return Object.fromEntries(Object.entries(value).filter(([k])=>!['refreshedAt','payrollRefreshedAt','lagSeconds','ageMs','cacheHit'].includes(k)).map(([k,v])=>[k,clean(k==='payrollSourceStatus'?Object.fromEntries(Object.entries(v).filter(([key])=>!['sync','complete','stale'].includes(key))):v)]));return value;}
- const hash=d=>createHash('sha256').update(JSON.stringify(clean(d??null))).digest('hex');
- try{
- for(const [variant,source] of Object.entries({before:original,after:patchAdminSpeed(original)})){
- const path='xiaoshu/system/admin-speed-'+randomBytes(10).toString('hex');
- const code=source+`\nrealtimeCacheWrite=async()=>{};const __readHandler=handler;handler=async function(request,response){const p=request.body?.params||{};if(request.user?.id!==${JSON.stringify(me.objectId)}||Date.now()>${Date.now()+3600000}||!${JSON.stringify(allowed)}.includes(p.operation)||p.refresh===true&&!['ops/coaches/list','ops/payroll/overview','ops/schedule/calendar'].includes(p.operation))return response.status(403).json({success:false});return __readHandler(request,response);};`;
- new Function(code);const row=await parse('/classes/Function','POST',{name:path,path,code,type:'standalone',enabled:true,params:[],paramList:[],respType:'json'});functions.push({...row,variant,path});
- }
- if(process.env.PERF_BROWSER)browser=await browserHarness({functions,token,me,base,out});
- const rounds=Number(process.env.PERF_RUNS||10);
- for(let round=0;round<rounds;round++)for(const item of cases){
- const pair=[];
- for(const fn of round%2?[...functions].reverse():functions){if(browser){const measured=await browser.measure(fn,item,round);fs.writeFileSync(out+'/'+item.page+'-'+fn.variant+'-latest.json',JSON.stringify({data:measured.data}),{mode:0o600});const {data,...metrics}=measured;const result={round,page:item.page,variant:fn.variant,ms:metrics.readyMs,success:true,hash:hash(data),...metrics};pair.push(result);results.push(result);continue;}const at=performance.now();const response=await fetch(base+'/api/functions/'+fn.path,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({token,params:item.params}),signal:AbortSignal.timeout(60000)});const body=await response.json();const result={round,page:item.page,variant:fn.variant,ms:Math.round(performance.now()-at),success:response.ok&&body.success===true,bytes:Buffer.byteLength(JSON.stringify(body)),hash:hash(body.data)};
- if(!result.success)throw Error(item.page+' '+fn.variant+' HTTP '+response.status+' '+String(body.message||body.error||'unsuccessful').slice(0,250));
- fs.writeFileSync(out+'/'+item.page+'-'+fn.variant+'-latest.json',JSON.stringify(body),{mode:0o600});pair.push(result);results.push(result);
- }
- const equal=pair[0].hash===pair[1].hash;console.log(JSON.stringify({round,page:item.page,equal,times:pair.map(r=>({variant:r.variant,ms:r.ms}))}));
- fs.writeFileSync(out+'/'+(process.env.PERF_OUTPUT||'api-paired.json'),JSON.stringify({at:new Date().toISOString(),results},null,2),{mode:0o600});
- }
- }finally{await browser?.close();for(const fn of functions){await parse('/classes/Function/'+fn.objectId,'DELETE');console.log('Removed '+fn.variant+' temporary gateway');}}
|