import { readFile } from "node:fs/promises"; import { linuxTcpSocketStats } from "./schema.ts"; const SOCKSTAT_PATH = "/proc/net/sockstat"; const RAW_MAX = 4096; function parseInt10(s) { const n = Number.parseInt(String(s), 10); return Number.isFinite(n) ? Math.trunc(n) : NaN; } function parseSockstat(content) { let socketsUsed = 0; let tcpInuse = 0; let tcpOrphan = 0; let tcpTw = 0; let tcpAlloc = 0; let tcpMemPages = 0; let parseOk = 1; let socketsOk = false; let tcpOk = false; for (const line of content.split("\n")) { const trimmed = line.trim(); if (trimmed.startsWith("sockets:")) { const parts = trimmed.split(/\s+/); const usedIdx = parts.indexOf("used"); if (usedIdx !== -1 && usedIdx + 1 < parts.length) { const v = parseInt10(parts[usedIdx + 1]); if (Number.isFinite(v)) { socketsUsed = v; socketsOk = true; } } } 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]] = parseInt10(parts[i + 1]); } const keys = ["inuse", "orphan", "tw", "alloc", "mem"]; if (keys.every((k) => Number.isFinite(map[k]))) { tcpInuse = map.inuse; tcpOrphan = map.orphan; tcpTw = map.tw; tcpAlloc = map.alloc; tcpMemPages = map.mem; tcpOk = true; } } } if (!socketsOk || !tcpOk) { parseOk = 0; socketsUsed = 0; tcpInuse = 0; tcpOrphan = 0; tcpTw = 0; tcpAlloc = 0; tcpMemPages = 0; } return { socketsUsed, tcpInuse, tcpOrphan, tcpTw, tcpAlloc, tcpMemPages, parseOk, }; } export async function compute(db, _peers) { const ts = Date.now(); let rawSockstat = ""; let row = { socketsUsed: 0, tcpInuse: 0, tcpOrphan: 0, tcpTw: 0, tcpAlloc: 0, tcpMemPages: 0, parseOk: 0, }; try { const content = await readFile(SOCKSTAT_PATH, "utf8"); rawSockstat = content.length > RAW_MAX ? content.slice(0, RAW_MAX) : content; row = parseSockstat(content); } catch { rawSockstat = ""; } await db.insert(linuxTcpSocketStats).values({ ts, socketsUsed: row.socketsUsed, tcpInuse: row.tcpInuse, tcpOrphan: row.tcpOrphan, tcpTw: row.tcpTw, tcpAlloc: row.tcpAlloc, tcpMemPages: row.tcpMemPages, parseOk: row.parseOk, rawSockstat, }); return { ts, socketsUsed: row.socketsUsed, tcpInuse: row.tcpInuse, tcpOrphan: row.tcpOrphan, tcpTw: row.tcpTw, tcpAlloc: row.tcpAlloc, tcpMemPages: row.tcpMemPages, parseOk: row.parseOk, rawSockstat, }; }