196 lines
4.3 KiB
TypeScript
196 lines
4.3 KiB
TypeScript
import fs from "node:fs"
|
|
import os from "node:os"
|
|
import type { SystemMetrics } from "~/types/system"
|
|
|
|
type CpuTimesSnapshot = {
|
|
idle: number
|
|
total: number
|
|
}
|
|
|
|
type NetworkTotals = {
|
|
rxBytes: number
|
|
txBytes: number
|
|
}
|
|
|
|
type NetworkSnapshot = NetworkTotals & {
|
|
timestamp: number
|
|
}
|
|
|
|
let lastCpuSnapshot: CpuTimesSnapshot | null = null
|
|
let lastNetworkSnapshot: NetworkSnapshot | null = null
|
|
let intervalId: NodeJS.Timeout | null = null
|
|
let latestSnapshot: SystemMetrics = createSnapshot({
|
|
cpuPercent: 0,
|
|
incomingMbps: 0,
|
|
outgoingMbps: 0
|
|
})
|
|
|
|
function createSnapshot(overrides: {
|
|
cpuPercent: number
|
|
incomingMbps: number
|
|
outgoingMbps: number
|
|
}): SystemMetrics {
|
|
const totalMemory = os.totalmem()
|
|
const freeMemory = os.freemem()
|
|
const usedMemory = totalMemory - freeMemory
|
|
const memoryPercent = totalMemory > 0 ? Math.round((usedMemory / totalMemory) * 100) : 0
|
|
|
|
return {
|
|
cpuPercent: overrides.cpuPercent,
|
|
memoryPercent,
|
|
totalMemory,
|
|
usedMemory,
|
|
incomingMbps: overrides.incomingMbps,
|
|
outgoingMbps: overrides.outgoingMbps,
|
|
sampledAt: new Date().toISOString()
|
|
}
|
|
}
|
|
|
|
function getCpuSnapshot(): CpuTimesSnapshot {
|
|
return os.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 getCpuUsagePercent() {
|
|
const currentSnapshot = getCpuSnapshot()
|
|
|
|
if (!lastCpuSnapshot) {
|
|
lastCpuSnapshot = currentSnapshot
|
|
return 0
|
|
}
|
|
|
|
const idleDelta = currentSnapshot.idle - lastCpuSnapshot.idle
|
|
const totalDelta = currentSnapshot.total - lastCpuSnapshot.total
|
|
lastCpuSnapshot = currentSnapshot
|
|
|
|
if (totalDelta <= 0) {
|
|
return 0
|
|
}
|
|
|
|
return Math.max(0, Math.min(100, Math.round((1 - idleDelta / totalDelta) * 100)))
|
|
}
|
|
|
|
function getNetworkTotals(): NetworkTotals | null {
|
|
try {
|
|
const content = fs.readFileSync("/proc/net/dev", "utf8")
|
|
|
|
return content
|
|
.split("\n")
|
|
.slice(2)
|
|
.map((line) => line.trim())
|
|
.filter(Boolean)
|
|
.reduce(
|
|
(totals, line) => {
|
|
const [namePart, valuesPart] = line.split(":")
|
|
const interfaceName = namePart?.trim()
|
|
|
|
if (!interfaceName || interfaceName === "lo" || !valuesPart) {
|
|
return totals
|
|
}
|
|
|
|
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)) {
|
|
totals.rxBytes += rxBytes
|
|
}
|
|
|
|
if (Number.isFinite(txBytes)) {
|
|
totals.txBytes += txBytes
|
|
}
|
|
|
|
return totals
|
|
},
|
|
{ rxBytes: 0, txBytes: 0 }
|
|
)
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
function getNetworkRatesMbps() {
|
|
const totals = getNetworkTotals()
|
|
const now = Date.now()
|
|
|
|
if (!totals) {
|
|
lastNetworkSnapshot = null
|
|
return {
|
|
incomingMbps: 0,
|
|
outgoingMbps: 0
|
|
}
|
|
}
|
|
|
|
const currentSnapshot: NetworkSnapshot = {
|
|
...totals,
|
|
timestamp: now
|
|
}
|
|
|
|
if (!lastNetworkSnapshot) {
|
|
lastNetworkSnapshot = currentSnapshot
|
|
return {
|
|
incomingMbps: 0,
|
|
outgoingMbps: 0
|
|
}
|
|
}
|
|
|
|
const elapsedSeconds = (currentSnapshot.timestamp - lastNetworkSnapshot.timestamp) / 1000
|
|
|
|
if (elapsedSeconds <= 0) {
|
|
lastNetworkSnapshot = currentSnapshot
|
|
return {
|
|
incomingMbps: 0,
|
|
outgoingMbps: 0
|
|
}
|
|
}
|
|
|
|
const incomingMbps = Math.max(
|
|
0,
|
|
Number((((currentSnapshot.rxBytes - lastNetworkSnapshot.rxBytes) * 8) / elapsedSeconds / 1000000).toFixed(2))
|
|
)
|
|
const outgoingMbps = Math.max(
|
|
0,
|
|
Number((((currentSnapshot.txBytes - lastNetworkSnapshot.txBytes) * 8) / elapsedSeconds / 1000000).toFixed(2))
|
|
)
|
|
|
|
lastNetworkSnapshot = currentSnapshot
|
|
|
|
return {
|
|
incomingMbps,
|
|
outgoingMbps
|
|
}
|
|
}
|
|
|
|
function refreshSnapshot() {
|
|
const cpuPercent = getCpuUsagePercent()
|
|
const { incomingMbps, outgoingMbps } = getNetworkRatesMbps()
|
|
|
|
latestSnapshot = createSnapshot({
|
|
cpuPercent,
|
|
incomingMbps,
|
|
outgoingMbps
|
|
})
|
|
}
|
|
|
|
export function getSystemMetricsSnapshot() {
|
|
return latestSnapshot
|
|
}
|
|
|
|
export default defineNitroPlugin(() => {
|
|
if (intervalId) {
|
|
return
|
|
}
|
|
|
|
refreshSnapshot()
|
|
intervalId = setInterval(refreshSnapshot, 2000)
|
|
})
|