diff --git a/js/main.js b/js/main.js index 03e6771..da51840 100644 --- a/js/main.js +++ b/js/main.js @@ -591,11 +591,13 @@ const ulData = []; const maxPoints = 80; - // Seed initial data + // Seed with zeros — graph populates with real samples from initLiveStats for (let i = 0; i < maxPoints; i++) { - dlData.push(30 + Math.random() * 40); - ulData.push(20 + Math.random() * 30); + dlData.push(0); + ulData.push(0); } + // Auto-scaling peak (starts at 10 Mbps floor) + let peakMbps = 10; function drawLine(data, color, alpha) { const w = canvas.width; @@ -609,7 +611,8 @@ for (let i = 0; i < data.length; i++) { const x = i * step; - const y = h - (data[i] / 100) * h; + const scaled = Math.min(100, (data[i] / peakMbps) * 100); + const y = h - (scaled / 100) * h; if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y); } @@ -647,32 +650,25 @@ } } - function updateStats() { - const dl = dlData[dlData.length - 1]; - const ul = ulData[ulData.length - 1]; - const dlEl = document.getElementById('dlSpeed'); - const ulEl = document.getElementById('ulSpeed'); - const pkEl = document.getElementById('packetCount'); - if (dlEl) dlEl.textContent = (dl * 0.032).toFixed(1) + ' Gbps'; - if (ulEl) ulEl.textContent = (ul * 0.028).toFixed(1) + ' Gbps'; - if (pkEl) pkEl.textContent = Math.floor(dl * 180).toLocaleString() + ' pkt/s'; - } + // Readouts (dlSpeed/ulSpeed/packetCount) are updated by initLiveStats with real values function animate() { ctx.clearRect(0, 0, canvas.width, canvas.height); drawGrid(); - // Push new data - const lastDl = dlData[dlData.length - 1]; - const lastUl = ulData[ulData.length - 1]; - dlData.push(Math.max(10, Math.min(95, lastDl + (Math.random() - 0.48) * 12))); - ulData.push(Math.max(5, Math.min(85, lastUl + (Math.random() - 0.48) * 10))); + // Pull latest real Mbps from shared state set by initLiveStats + const stats = window.__serverStats || { dlMbps: 0, ulMbps: 0 }; + dlData.push(stats.dlMbps || 0); + ulData.push(stats.ulMbps || 0); if (dlData.length > maxPoints) dlData.shift(); if (ulData.length > maxPoints) ulData.shift(); - drawLine(dlData, '#333333', 0.9); - drawLine(ulData, '#00a8ff', 0.6); - updateStats(); + // Smooth auto-scaling peak + const curMax = Math.max.apply(null, dlData.concat(ulData).concat([1])); + peakMbps = peakMbps * 0.95 + Math.max(10, curMax * 1.2) * 0.05; + + drawLine(dlData, '#00ff9d', 0.9); // download = green + drawLine(ulData, '#00a8ff', 0.7); // upload = blue requestAnimationFrame(animate); } @@ -818,67 +814,125 @@ }); } - // ─── LIVE SERVER STATS (from API) ─── + // ─── LIVE SERVER STATS (from API) — REAL DATA ─── + // Shared state used by the network graph + window.__serverStats = { + lastRx: null, lastTx: null, lastT: null, + dlMbps: 0, ulMbps: 0, bwPct: 0 + }; + + function formatUptime(sec) { + sec = Math.floor(sec); + const d = Math.floor(sec / 86400); + const h = Math.floor((sec % 86400) / 3600); + const m = Math.floor((sec % 3600) / 60); + return d + 'd ' + String(h).padStart(2, '0') + 'h ' + String(m).padStart(2, '0') + 'm'; + } + + function applyBar(barId, valId, value, unit) { + const barEl = document.getElementById(barId); + const valEl = document.getElementById(valId); + if (!barEl || !valEl) return; + const v = Math.max(0, Math.min(100, value)); + barEl.style.width = v + '%'; + valEl.textContent = Math.round(v) + (unit || '%'); + if (v > 85) { + barEl.style.background = 'linear-gradient(90deg, #ff2d2d, rgba(255,71,87,0.4))'; + barEl.style.boxShadow = '0 0 8px rgba(255,71,87,0.4)'; + valEl.style.color = '#ff2d2d'; + } else if (v > 70) { + barEl.style.background = 'linear-gradient(90deg, #c9a227, rgba(255,165,2,0.4))'; + barEl.style.boxShadow = '0 0 8px rgba(255,165,2,0.3)'; + valEl.style.color = '#c9a227'; + } else { + barEl.style.background = ''; + barEl.style.boxShadow = ''; + valEl.style.color = ''; + } + } + function initLiveStats() { + // Assumed max link capacity for bandwidth % scaling (1 Gbps) + const LINK_MBPS = 1000; + function fetchStats() { fetch(API_BASE + '/stats') .then(r => r.json()) .then(d => { - // Update metric bars with real data - const metrics = [ - { bar: 'cpuBar', val: 'cpuVal', value: d.cpu_percent }, - { bar: 'memBar', val: 'memVal', value: d.memory_percent }, - { bar: 'diskBar', val: 'diskVal', value: d.disk_percent }, - ]; - metrics.forEach(m => { - const barEl = document.getElementById(m.bar); - const valEl = document.getElementById(m.val); - if (!barEl || !valEl) return; - barEl.style.width = m.value + '%'; - valEl.textContent = Math.round(m.value) + '%'; - if (m.value > 85) { - barEl.style.background = 'linear-gradient(90deg, #ff2d2d, rgba(255,71,87,0.4))'; - barEl.style.boxShadow = '0 0 8px rgba(255,71,87,0.4)'; - valEl.style.color = '#ff2d2d'; - } else if (m.value > 70) { - barEl.style.background = 'linear-gradient(90deg, #c9a227, rgba(255,165,2,0.4))'; - barEl.style.boxShadow = '0 0 8px rgba(255,165,2,0.3)'; - valEl.style.color = '#c9a227'; - } else { - barEl.style.background = ''; - barEl.style.boxShadow = ''; - valEl.style.color = ''; - } - }); + // CPU / MEM / DISK bars + applyBar('cpuBar', 'cpuVal', d.cpu_percent); + applyBar('memBar', 'memVal', d.memory_percent); + applyBar('diskBar', 'diskVal', d.disk_percent); - // Update uptime from real data - const uptimeEl = document.getElementById('uptime'); + // Bandwidth — compute MB/s delta from network_rx_bytes + network_tx_bytes + const now = (d.timestamp || Date.now() / 1000); + const s = window.__serverStats; + if (s.lastRx !== null && s.lastT !== null && now > s.lastT) { + const dt = Math.max(0.1, now - s.lastT); + const rxBps = Math.max(0, (d.network_rx_bytes - s.lastRx) / dt); + const txBps = Math.max(0, (d.network_tx_bytes - s.lastTx) / dt); + const rxMbps = (rxBps * 8) / 1e6; + const txMbps = (txBps * 8) / 1e6; + s.dlMbps = rxMbps; + s.ulMbps = txMbps; + const totalMbps = rxMbps + txMbps; + s.bwPct = Math.min(100, (totalMbps / LINK_MBPS) * 100); + applyBar('bwBar', 'bwVal', s.bwPct); + + // Network graph stat readouts + const dlEl = document.getElementById('dlSpeed'); + const ulEl = document.getElementById('ulSpeed'); + const pkEl = document.getElementById('packetCount'); + const fmtSpeed = mbps => mbps >= 1000 ? (mbps / 1000).toFixed(2) + ' Gbps' + : mbps >= 1 ? mbps.toFixed(1) + ' Mbps' + : (mbps * 1000).toFixed(0) + ' Kbps'; + if (dlEl) dlEl.textContent = fmtSpeed(rxMbps); + if (ulEl) ulEl.textContent = fmtSpeed(txMbps); + if (pkEl) pkEl.textContent = (d.active_connections || 0).toLocaleString() + ' conns'; + } else { + // Seed on first sample + applyBar('bwBar', 'bwVal', 0); + } + s.lastRx = d.network_rx_bytes; + s.lastTx = d.network_tx_bytes; + s.lastT = now; + + // Uptime (HTML id is serverUptime) + const uptimeEl = document.getElementById('serverUptime') || document.getElementById('uptime'); if (uptimeEl && d.uptime_seconds) { - const totalSec = Math.floor(d.uptime_seconds); - const days = Math.floor(totalSec / 86400); - const hours = Math.floor((totalSec % 86400) / 3600); - const mins = Math.floor((totalSec % 3600) / 60); - uptimeEl.textContent = days + 'd ' + String(hours).padStart(2, '0') + 'h ' + String(mins).padStart(2, '0') + 'm'; + uptimeEl.textContent = formatUptime(d.uptime_seconds); } - // Update server health + // Server health — weighted score from cpu/mem/disk const healthEl = document.getElementById('serverHealth'); if (healthEl) { - const health = Math.round(100 - (d.cpu_percent * 0.3 + d.memory_percent * 0.3 + d.disk_percent * 0.4) / 3); - healthEl.textContent = Math.min(99, Math.max(80, health)) + '%'; + const penalty = (d.cpu_percent * 0.35 + d.memory_percent * 0.35 + d.disk_percent * 0.30); + const health = Math.round(100 - penalty * 0.35); + healthEl.textContent = Math.min(99, Math.max(40, health)) + '%'; } - // Container counts + // Power panel — use inverse of CPU load as "reliability" % + const powerEl = document.getElementById('powerPct'); + if (powerEl) { + const rel = Math.max(60, Math.min(100, 100 - d.cpu_percent * 0.4)); + powerEl.innerHTML = Math.round(rel) + '%'; + } + + // Containers const containerEl = document.getElementById('containerUp'); const containerTotalEl = document.querySelector('.container-total'); + const containerBar = document.getElementById('containerBar'); if (containerEl) containerEl.textContent = d.container_running; if (containerTotalEl) containerTotalEl.textContent = d.container_total; + if (containerBar && d.container_total) { + containerBar.style.width = ((d.container_running / d.container_total) * 100) + '%'; + } }) .catch(() => {}); } fetchStats(); - setInterval(fetchStats, 10000); // refresh every 10s + setInterval(fetchStats, 5000); // refresh every 5s } // ─── LIVE WEATHER ─── @@ -940,10 +994,10 @@ initHUDFlickers(); initPanelGlow(); initNetworkGraph(); - initMetricBars(); + // initMetricBars(); // disabled — real data from /api/stats via initLiveStats initScanBar(); - initPowerFlicker(); - initServerHealth(); + // initPowerFlicker(); // disabled — real load_avg-based via initLiveStats + // initServerHealth(); // disabled — real health computed in initLiveStats // Live API integrations initBlogFeed();