fix(station): dead code cleanup, 0pct ring bug, Syncthing removal, SRI, canvas pause

Made-with: Cursor
This commit is contained in:
posimai 2026-04-12 10:43:17 +09:00
parent 7aa79f4a7d
commit 65c358c58d
2 changed files with 12 additions and 19 deletions

View File

@ -10,7 +10,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@300;400;500&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@300;400;500&display=swap" rel="stylesheet">
<script src="https://unpkg.com/lucide@0.344.0/dist/umd/lucide.min.js"></script> <script src="https://unpkg.com/lucide@0.344.0/dist/umd/lucide.min.js" integrity="sha384-tTkFttkBclaU1cloKwOi9xk3pbao3VZxTjLNBt8iFABWDBQibbAbWpVmO28zMuxq" crossorigin="anonymous"></script>
<style> <style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root { :root {
@ -359,8 +359,6 @@ const hist = {cpu:[], load:[]};
const svcHist = {}; const svcHist = {};
const svcLatHist = {}; const svcLatHist = {};
SERVICES.forEach(s => { svcHist[s.id] = []; svcLatHist[s.id] = []; }); SERVICES.forEach(s => { svcHist[s.id] = []; svcLatHist[s.id] = []; });
// メトリクスのグローバルキャッシュupdateStream の setInterval から参照)
let _metrics = { cpuPct:0, memPct:0, diskPct:0, loadAvg:[0,0,0], uptimeS:0, sessions:0, hostname:'ubuntu-pc', nodeVer:'' };
let streamData = null; let streamData = null;
function p(n){ return String(n).padStart(2,'0'); } function p(n){ return String(n).padStart(2,'0'); }
@ -428,12 +426,9 @@ async function fetchHealth(){
window._cpuCount=cpuCount; window._cpuCount=cpuCount;
document.getElementById('cpu-val').textContent=`${cpuPct}%`; document.getElementById('cpu-val').textContent=`${cpuPct}%`;
renderBinBar('cpu-bar',cpuPct,60,80);
document.getElementById('mem-val').textContent=`${data.mem_used_mb}/${data.mem_total_mb}MB (${memPct}%)`; document.getElementById('mem-val').textContent=`${data.mem_used_mb}/${data.mem_total_mb}MB (${memPct}%)`;
renderBinBar('mem-bar',memPct,65,85);
if(data.disk){ if(data.disk){
document.getElementById('disk-val').textContent=`${data.disk.used_gb}/${data.disk.total_gb}GB (${diskPct}%)`; document.getElementById('disk-val').textContent=`${data.disk.used_gb}/${data.disk.total_gb}GB (${diskPct}%)`;
renderBinBar('disk-bar',diskPct,75,90);
} }
document.getElementById('cpu-count-label').textContent=`(core:${cpuCount})`; document.getElementById('cpu-count-label').textContent=`(core:${cpuCount})`;
['load-1','load-5','load-15'].forEach((id,i)=>{ ['load-1','load-5','load-15'].forEach((id,i)=>{
@ -673,6 +668,7 @@ function startCountdown(){
async function runRefresh(){ async function runRefresh(){
const devOk=await fetchHealth(); const devOk=await fetchHealth();
checkAllServices(devOk); checkAllServices(devOk);
fetchVpsHealth();
const now=new Date().toLocaleTimeString('ja-JP',{hour:'2-digit',minute:'2-digit',second:'2-digit'}); const now=new Date().toLocaleTimeString('ja-JP',{hour:'2-digit',minute:'2-digit',second:'2-digit'});
document.getElementById('last-checked').textContent=`最終更新: ${now}`; document.getElementById('last-checked').textContent=`最終更新: ${now}`;
startCountdown(); startCountdown();
@ -736,10 +732,8 @@ async function fetchVpsHealth(){
const diskPct=d.disk?.use_pct??0; const diskPct=d.disk?.use_pct??0;
document.getElementById('vps-load').textContent=d.load_avg?`${d.load_avg[0]} / ${d.load_avg[1]}`:'—'; document.getElementById('vps-load').textContent=d.load_avg?`${d.load_avg[0]} / ${d.load_avg[1]}`:'—';
document.getElementById('vps-mem').textContent=d.mem_total_mb?`${d.mem_used_mb}/${d.mem_total_mb}MB (${memPct}%)`:'—'; document.getElementById('vps-mem').textContent=d.mem_total_mb?`${d.mem_used_mb}/${d.mem_total_mb}MB (${memPct}%)`:'—';
renderBinBar('vps-mem-bar',memPct,65,85);
if(d.disk){ if(d.disk){
document.getElementById('vps-disk').textContent=`${d.disk.used_gb}/${d.disk.total_gb}GB (${diskPct}%)`; document.getElementById('vps-disk').textContent=`${d.disk.used_gb}/${d.disk.total_gb}GB (${diskPct}%)`;
renderBinBar('vps-disk-bar',diskPct,75,90);
} }
document.getElementById('vps-uptime').textContent=formatUptime(d.uptime_s||0); document.getElementById('vps-uptime').textContent=formatUptime(d.uptime_s||0);
document.getElementById('vps-users').textContent=String(d.users??'—'); document.getElementById('vps-users').textContent=String(d.users??'—');
@ -752,8 +746,6 @@ async function fetchVpsHealth(){
.forEach(id=>{ const el=document.getElementById(id); if(el) el.textContent='ERR'; }); .forEach(id=>{ const el=document.getElementById(id); if(el) el.textContent='ERR'; });
} }
} }
fetchVpsHealth();
setInterval(fetchVpsHealth, 30000);
// ── キーボードショートカット ──────────────────────────────────── // ── キーボードショートカット ────────────────────────────────────
document.addEventListener('keydown', e => { document.addEventListener('keydown', e => {
@ -803,11 +795,11 @@ document.addEventListener('keydown', e => {
const sat = Math.round(best.sat + (100 - best.sat) * _critProgress * 0.5); const sat = Math.round(best.sat + (100 - best.sat) * _critProgress * 0.5);
return { hue, sat, alpha }; return { hue, sat, alpha };
} }
let rafId = null;
function draw(){ function draw(){
t++; t++;
// Gradually shift critProgress toward target (0 or 1)
const critTarget = window._systemCrit ? 1 : 0; const critTarget = window._systemCrit ? 1 : 0;
_critProgress += (critTarget - _critProgress) * 0.008; // ~3s transition _critProgress += (critTarget - _critProgress) * 0.008;
ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.font = `${FONT_SIZE}px 'JetBrains Mono', monospace`; ctx.font = `${FONT_SIZE}px 'JetBrains Mono', monospace`;
cols.forEach((col, i) => { cols.forEach((col, i) => {
@ -828,9 +820,12 @@ document.addEventListener('keydown', e => {
col.y += col.speed; col.y += col.speed;
if(col.y - col.len*FONT_SIZE > canvas.height){ col.y=-FONT_SIZE*2; col.speed=1.2+Math.random()*3.5; col.len=8+Math.floor(Math.random()*20); col.chars=[]; col.opacity=0.3+Math.random()*0.5; } if(col.y - col.len*FONT_SIZE > canvas.height){ col.y=-FONT_SIZE*2; col.speed=1.2+Math.random()*3.5; col.len=8+Math.floor(Math.random()*20); col.chars=[]; col.opacity=0.3+Math.random()*0.5; }
}); });
requestAnimationFrame(draw); rafId = requestAnimationFrame(draw);
} }
draw(); function startCanvas(){ if(!rafId) rafId = requestAnimationFrame(draw); }
function stopCanvas(){ if(rafId){ cancelAnimationFrame(rafId); rafId=null; } }
document.addEventListener('visibilitychange', () => { document.hidden ? stopCanvas() : startCanvas(); });
startCanvas();
})(); })();
</script> </script>
</body> </body>

View File

@ -10,7 +10,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@300;400;500&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@300;400;500&display=swap" rel="stylesheet">
<script src="https://unpkg.com/lucide@0.344.0/dist/umd/lucide.min.js"></script> <script src="https://unpkg.com/lucide@0.344.0/dist/umd/lucide.min.js" integrity="sha384-tTkFttkBclaU1cloKwOi9xk3pbao3VZxTjLNBt8iFABWDBQibbAbWpVmO28zMuxq" crossorigin="anonymous"></script>
<style> <style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root { :root {
@ -335,7 +335,7 @@ const SERVICES = [
{id:'posimai-dev',name:'posimai-dev', desc:'ブラウザターミナル + Claude Code',url:HEALTH_URL, isHealth:true}, {id:'posimai-dev',name:'posimai-dev', desc:'ブラウザターミナル + Claude Code',url:HEALTH_URL, isHealth:true},
{id:'posimai-api',name:'Posimai API',desc:'Node.js / Express — VPS 本番', url:'/api/vps-health', isHealth:false, proxy:true}, {id:'posimai-api',name:'Posimai API',desc:'Node.js / Express — VPS 本番', url:'/api/vps-health', isHealth:false, proxy:true},
{id:'gitea', name:'Gitea', desc:'ローカル Git バックアップ', url:'/api/check?url=http://100.76.7.3:3000', isHealth:false, proxy:true}, {id:'gitea', name:'Gitea', desc:'ローカル Git バックアップ', url:'/api/check?url=http://100.76.7.3:3000', isHealth:false, proxy:true},
{id:'syncthing', name:'Syncthing', desc:'ファイル同期 GUI', url:'/api/check?url=http://100.77.11.43:8384', isHealth:false, proxy:true}, {id:'uptime-kuma',name:'Uptime Kuma', desc:'死活監視 — NAS Docker', url:'/api/check?url=http://100.76.7.3:3002', isHealth:false, proxy:true},
{id:'vercel', name:'Vercel', desc:'PWA ホスティング (27本)', url:'https://vercel.com', isHealth:false}, {id:'vercel', name:'Vercel', desc:'PWA ホスティング (27本)', url:'https://vercel.com', isHealth:false},
{id:'github', name:'GitHub', desc:'ソースコード管理', url:'https://github.com/posimai', isHealth:false}, {id:'github', name:'GitHub', desc:'ソースコード管理', url:'https://github.com/posimai', isHealth:false},
]; ];
@ -343,8 +343,6 @@ const hist = {cpu:[], load:[]};
const svcHist = {}; const svcHist = {};
const svcLatHist = {}; const svcLatHist = {};
SERVICES.forEach(s => { svcHist[s.id] = []; svcLatHist[s.id] = []; }); SERVICES.forEach(s => { svcHist[s.id] = []; svcLatHist[s.id] = []; });
// メトリクスのグローバルキャッシュupdateStream の setInterval から参照)
let _metrics = { cpuPct:0, memPct:0, diskPct:0, loadAvg:[0,0,0], uptimeS:0, sessions:0, hostname:'ubuntu-pc', nodeVer:'' };
let streamData = null; let streamData = null;
function p(n){ return String(n).padStart(2,'0'); } function p(n){ return String(n).padStart(2,'0'); }
@ -375,7 +373,7 @@ function updateRing(fillId,valId,pct,circ,base,warn,crit){
fill.style.strokeDashoffset=circ*(1-Math.min(pct,100)/100); fill.style.strokeDashoffset=circ*(1-Math.min(pct,100)/100);
const color=pct>80?(crit||'#F87171'):pct>60?(warn||'#FB923C'):(base||'#22D3EE'); const color=pct>80?(crit||'#F87171'):pct>60?(warn||'#FB923C'):(base||'#22D3EE');
fill.style.stroke=color; fill.style.stroke=color;
valEl.textContent=pct>0?`${pct}%`:'—'; valEl.textContent=`${pct}%`;
valEl.style.fill=pct>80?'#F87171':pct>60?'#FB923C':'var(--text)'; valEl.style.fill=pct>80?'#F87171':pct>60?'#FB923C':'var(--text)';
} }