KeyHunter parser v10 + 18 scanners + tests (synthetic fixtures only, no keys/db/tokens)
This commit is contained in:
71
_agent_dash.js
Normal file
71
_agent_dash.js
Normal file
@@ -0,0 +1,71 @@
|
||||
|
||||
async function jget(u){const r=await fetch(u);return r.json();}
|
||||
async function post(u){const r=await fetch(u,{method:'POST'});return r.json();}
|
||||
|
||||
async function refresh(){
|
||||
try{
|
||||
const s=await jget('/api/stats');
|
||||
el('m-total').textContent=s.total.toLocaleString('ru');
|
||||
el('m-today').textContent=s.today.toLocaleString('ru');
|
||||
const alive=Object.values(s.engines).filter(e=>e.alive).length;
|
||||
el('m-eng').textContent=alive+' / '+Object.keys(s.engines).length;
|
||||
el('m-ts').textContent=s.ts;
|
||||
// движки
|
||||
const box=el('eng');box.innerHTML='';
|
||||
for(const [id,e] of Object.entries(s.engines)){
|
||||
const c=document.createElement('div');c.className='card';
|
||||
c.innerHTML=`<div><span class="dot ${e.alive?'on':'off'}"></span><b>${id}</b><div style="color:var(--dim);font-size:12px">${e.desc}${e.auto?' · auto':''}</div></div>`;
|
||||
const btn=document.createElement('button');
|
||||
btn.textContent=e.alive?'стоп':'старт';
|
||||
if(e.alive)btn.className='stop';
|
||||
btn.onclick=async()=>{e.alive?await post('/api/engine/'+id+'/stop'):await post('/api/engine/'+id+'/start');refresh();};
|
||||
c.appendChild(btn);box.appendChild(c);
|
||||
}
|
||||
// статусы
|
||||
const st=el('t-status');st.innerHTML='';
|
||||
const mx=Math.max(...s.by_status.map(x=>x.n),1);
|
||||
for(const r of s.by_status){
|
||||
const tr=document.createElement('tr');
|
||||
tr.innerHTML=`<td><span class="badge b-${r.status}">${r.status}</span></td><td>${r.n.toLocaleString('ru')}</td>
|
||||
<td style="width:40%"><div class="bar"><i style="width:${(100*r.n/mx).toFixed(0)}%"></i></div></td>`;
|
||||
st.appendChild(tr);
|
||||
}
|
||||
// провайдеры
|
||||
const pv=el('t-prov');pv.innerHTML='';
|
||||
for(const r of s.by_prov){
|
||||
const tr=document.createElement('tr');
|
||||
tr.innerHTML=`<td>${r.prov}</td><td>${r.n.toLocaleString('ru')}</td>`;
|
||||
tr.style.cursor='pointer';
|
||||
tr.onclick=()=>{el('f-prov').value=r.prov;loadKeys();};
|
||||
pv.appendChild(tr);
|
||||
}
|
||||
loadKeys();
|
||||
loadLog();
|
||||
}catch(e){console.error(e);}
|
||||
}
|
||||
|
||||
async function loadKeys(){
|
||||
const st=el('f-status').value,pv=el('f-prov').value,lim=el('f-limit').value||50;
|
||||
const d=await jget(`/api/keys?status=${st}&prov=${pv}&limit=${lim}`);
|
||||
const t=el('t-keys');t.innerHTML='';
|
||||
for(const r of d.rows){
|
||||
const tr=document.createElement('tr');
|
||||
tr.innerHTML=`<td><span class="badge b-${r.status}">${r.status}</span></td><td>${r.prov}</td>
|
||||
<td title="${r.val}">${r.val}</td><td title="${r.repo||''}">${r.repo||''}</td><td>${r.found||''}</td>`;
|
||||
t.appendChild(tr);
|
||||
}
|
||||
el('k-count').textContent=d.rows.length+' показано';
|
||||
}
|
||||
|
||||
async function loadLog(){
|
||||
const r=await fetch('/api/log?engine='+el('f-log').value);
|
||||
el('log').textContent=await r.text();
|
||||
el('log').scrollTop=el('log').scrollHeight;
|
||||
}
|
||||
|
||||
function el(id){return document.getElementById(id);}
|
||||
function exportKeys(){const st=el('f-status').value,pv=el('f-prov').value;
|
||||
window.open(`/api/export?status=${st}&prov=${pv}`,'_blank');}
|
||||
|
||||
refresh();
|
||||
setInterval(refresh,5000);
|
||||
Reference in New Issue
Block a user