// src/index.ts import { loadavg, totalmem, freemem, uptime } from "node:os"; import { execSync } from "node:child_process"; import { readFile } from "node:fs/promises"; // src/schema.ts import { integer, real, sqliteTable } from "drizzle-orm/sqlite-core"; var snapshots = sqliteTable("snapshots", { ts: integer("ts").primaryKey(), cpuLoad1m: real("cpu_load_1m").notNull(), cpuLoad5m: real("cpu_load_5m").notNull(), cpuLoad15m: real("cpu_load_15m").notNull(), memTotalMB: integer("mem_total_mb").notNull(), memUsedMB: integer("mem_used_mb").notNull(), memUsedPct: real("mem_used_pct").notNull(), diskTotalGB: real("disk_total_gb").notNull(), diskUsedGB: real("disk_used_gb").notNull(), diskUsedPct: real("disk_used_pct").notNull(), uptimeSec: integer("uptime_sec").notNull(), // TCP socket stats (merged from linux-tcp-socket-stats) socketsUsed: integer("sockets_used"), tcpInuse: integer("tcp_inuse"), tcpOrphan: integer("tcp_orphan"), tcpTw: integer("tcp_tw"), tcpAlloc: integer("tcp_alloc"), tcpMemPages: integer("tcp_mem_pages") }); // src/index.ts var SOCKSTAT_PATH = "/proc/net/sockstat"; function parseSockstat(content) { let socketsUsed = 0, tcpInuse = 0, tcpOrphan = 0, tcpTw = 0, tcpAlloc = 0, tcpMemPages = 0; for (const line of content.split("\n")) { const trimmed = line.trim(); if (trimmed.startsWith("sockets:")) { const parts = trimmed.split(/\s+/); const idx = parts.indexOf("used"); if (idx !== -1 && idx + 1 < parts.length) { socketsUsed = Number.parseInt(parts[idx + 1], 10) || 0; } } else if (trimmed.startsWith("TCP:")) { const parts = trimmed.split(/\s+/); const map = {}; for (let i = 1; i + 1 < parts.length; i += 2) { map[parts[i]] = Number.parseInt(parts[i + 1], 10) || 0; } tcpInuse = map.inuse ?? 0; tcpOrphan = map.orphan ?? 0; tcpTw = map.tw ?? 0; tcpAlloc = map.alloc ?? 0; tcpMemPages = map.mem ?? 0; } } return { socketsUsed, tcpInuse, tcpOrphan, tcpTw, tcpAlloc, tcpMemPages }; } async function compute(_signal) { const [load1, load5, load15] = loadavg(); const memTotal = totalmem(); const memFree = freemem(); const memUsed = memTotal - memFree; const memTotalMB = Math.round(memTotal / 1024 / 1024); const memUsedMB = Math.round(memUsed / 1024 / 1024); const memUsedPct = Math.round(memUsed / memTotal * 1e4) / 100; let diskTotalGB = 0, diskUsedGB = 0, diskUsedPct = 0; try { const df = execSync("df -B1 / | tail -1", { encoding: "utf-8" }).trim(); const parts = df.split(/\s+/); const total = Number(parts[1]); const used = Number(parts[2]); diskTotalGB = Math.round(total / 1024 / 1024 / 1024 * 100) / 100; diskUsedGB = Math.round(used / 1024 / 1024 / 1024 * 100) / 100; diskUsedPct = total > 0 ? Math.round(used / total * 1e4) / 100 : 0; } catch { } let tcp = { socketsUsed: 0, tcpInuse: 0, tcpOrphan: 0, tcpTw: 0, tcpAlloc: 0, tcpMemPages: 0 }; try { const content = await readFile(SOCKSTAT_PATH, "utf8"); tcp = parseSockstat(content); } catch { } const ts = Date.now(); const uptimeSec = Math.round(uptime()); return { ts, cpuLoad1m: load1, cpuLoad5m: load5, cpuLoad15m: load15, memTotalMB, memUsedMB, memUsedPct, diskTotalGB, diskUsedGB, diskUsedPct, uptimeSec, socketsUsed: tcp.socketsUsed, tcpInuse: tcp.tcpInuse, tcpOrphan: tcp.tcpOrphan, tcpTw: tcp.tcpTw, tcpAlloc: tcp.tcpAlloc, tcpMemPages: tcp.tcpMemPages }; } export { compute, snapshots as table };