import fs from "node:fs" import os from "node:os" type CpuTimesSnapshot = { idle: number total: number } type NetworkSnapshot = { rxBytes: number txBytes: number timestamp: number } let previousNetworkSnapshot: NetworkSnapshot | null = null function getCpuSnapshot(): CpuTimesSnapshot { const cpus = os.cpus() return cpus.reduce( (snapshot, cpu) => { const total = Object.values(cpu.times).reduce((sum, value) => sum + value, 0) snapshot.idle += cpu.times.idle snapshot.total += total return snapshot }, {idle: 0, total: 0} ) } function wait(durationMs: number) { return new Promise((resolve) => { setTimeout(resolve, durationMs) }) } async function getCpuUsagePercent(sampleMs: number) { const start = getCpuSnapshot() await wait(sampleMs) const end = getCpuSnapshot() const idleDelta = end.idle - start.idle const totalDelta = end.total - start.total if (totalDelta <= 0) { return 0 } return Math.max(0, Math.min(100, Math.round((1 - idleDelta / totalDelta) * 100))) } function getNetworkTotals() { try { const content = fs.readFileSync("/proc/net/dev", "utf8") const totals = content .split("\n") .slice(2) .map((line) => line.trim()) .filter(Boolean) .reduce( (accumulator, line) => { const [namePart, valuesPart] = line.split(":") const interfaceName = namePart?.trim() if (!interfaceName || interfaceName === "lo" || !valuesPart) { return accumulator } const values = valuesPart.trim().split(/\s+/) const rxBytes = Number.parseInt(values[0] || "0", 10) const txBytes = Number.parseInt(values[8] || "0", 10) if (Number.isFinite(rxBytes)) { accumulator.rxBytes += rxBytes } if (Number.isFinite(txBytes)) { accumulator.txBytes += txBytes } return accumulator }, {rxBytes: 0, txBytes: 0} ) return totals } catch { return null } } function getNetworkRatesMbps() { const totals = getNetworkTotals() const now = Date.now() if (!totals) { previousNetworkSnapshot = null return { incomingMbps: 0, outgoingMbps: 0 } } const currentSnapshot: NetworkSnapshot = { ...totals, timestamp: now } if (!previousNetworkSnapshot) { previousNetworkSnapshot = currentSnapshot return { incomingMbps: 0, outgoingMbps: 0 } } const elapsedSeconds = (currentSnapshot.timestamp - previousNetworkSnapshot.timestamp) / 1000 if (elapsedSeconds <= 0) { previousNetworkSnapshot = currentSnapshot return { incomingMbps: 0, outgoingMbps: 0 } } const incomingMbps = Math.max( 0, Number((((currentSnapshot.rxBytes - previousNetworkSnapshot.rxBytes) * 8) / elapsedSeconds / 1000000).toFixed(2)) ) const outgoingMbps = Math.max( 0, Number((((currentSnapshot.txBytes - previousNetworkSnapshot.txBytes) * 8) / elapsedSeconds / 1000000).toFixed(2)) ) previousNetworkSnapshot = currentSnapshot return { incomingMbps, outgoingMbps } } export default defineEventHandler(async () => { const totalMemory = os.totalmem() const freeMemory = os.freemem() const usedMemory = totalMemory - freeMemory const memoryPercent = totalMemory > 0 ? Math.round((usedMemory / totalMemory) * 100) : 0 const cpuPercent = await getCpuUsagePercent(200) const {incomingMbps, outgoingMbps} = getNetworkRatesMbps() return { cpuPercent, memoryPercent, totalMemory, usedMemory, incomingMbps, outgoingMbps, sampledAt: new Date().toISOString() } })