UNPKG

@foxglove/ws-protocol-examples

Version:

Foxglove WebSocket protocol examples

163 lines 6.57 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const ws_protocol_1 = require("@foxglove/ws-protocol"); const commander_1 = require("commander"); const debug_1 = tslib_1.__importDefault(require("debug")); const os_1 = tslib_1.__importDefault(require("os")); const ws_1 = require("ws"); const boxen_1 = tslib_1.__importDefault(require("../boxen")); const setupSigintHandler_1 = require("./util/setupSigintHandler"); const log = (0, debug_1.default)("foxglove:sysmon"); debug_1.default.enable("foxglove:*"); // eslint-disable-next-line @typescript-eslint/promise-function-async function delay(durationSec) { return new Promise((resolve) => setTimeout(resolve, durationSec * 1000)); } function getStats(prevStats) { let cpuTotal = 0; let idleTotal = 0; const cpus = []; os_1.default.cpus().forEach((cpu, i) => { const total = cpu.times.idle + cpu.times.user + cpu.times.nice + cpu.times.sys + cpu.times.irq; let usage = 0; const prevTimes = prevStats?.cpus[i]?.times; if (prevTimes) { const prevTotal = prevTimes.idle + prevTimes.user + prevTimes.nice + prevTimes.sys + prevTimes.irq; cpuTotal += total - prevTotal; idleTotal += cpu.times.idle - prevTimes.idle; usage = 1 - (cpu.times.idle - prevTimes.idle) / (total - prevTotal); } cpus.push({ ...cpu, usage }); }); const networkInterfaces = []; for (const [name, ifaces] of Object.entries(os_1.default.networkInterfaces())) { if (ifaces) { networkInterfaces.push(...ifaces.map((iface) => ({ name, ...iface }))); } } return { hostname: os_1.default.hostname(), platform: os_1.default.platform(), type: os_1.default.type(), arch: os_1.default.arch(), version: os_1.default.version(), release: os_1.default.release(), endianness: os_1.default.endianness(), uptime: os_1.default.uptime(), freemem: os_1.default.freemem(), totalmem: os_1.default.totalmem(), cpus, total_cpu_usage: 1 - idleTotal / cpuTotal, loadavg: os_1.default.loadavg(), networkInterfaces, }; } async function main() { const server = new ws_protocol_1.FoxgloveServer({ name: "sysmon" }); const port = 8765; const ws = new ws_1.WebSocketServer({ port, handleProtocols: (protocols) => server.handleProtocols(protocols), }); (0, setupSigintHandler_1.setupSigintHandler)(log, ws); ws.on("listening", () => { void (0, boxen_1.default)(`📡 Server listening on localhost:${port}. To see data, visit:\n` + `https://app.foxglove.dev/~/view?ds=foxglove-websocket&ds.url=ws://localhost:${port}/`, { borderStyle: "round", padding: 1 }).then(log); }); ws.on("connection", (conn, req) => { const name = `${req.socket.remoteAddress}:${req.socket.remotePort}`; server.handleConnection(conn, name); }); const ch1 = server.addChannel({ topic: "system_stats", encoding: "json", schemaName: "Stats", schema: JSON.stringify({ type: "object", properties: { hostname: { type: "string" }, platform: { type: "string" }, type: { type: "string" }, arch: { type: "string" }, version: { type: "string" }, release: { type: "string" }, endianness: { type: "string" }, uptime: { type: "number" }, freemem: { type: "number" }, totalmem: { type: "number" }, cpus: { type: "array", items: { type: "object", properties: { model: { type: "string" }, speed: { type: "number" }, usage: { type: "number" }, times: { type: "object", properties: { user: { type: "number" }, nice: { type: "number" }, sys: { type: "number" }, idle: { type: "number" }, irq: { type: "number" }, }, }, }, }, }, total_cpu_usage: { type: "number" }, loadavg: { type: "array", items: { type: "number" } }, networkInterfaces: { type: "array", items: { type: "object", properties: { name: { type: "string" }, family: { type: "string" }, address: { type: "string" }, netmask: { type: "string" }, mac: { type: "string" }, internal: { type: "boolean" }, cidr: { type: "string" }, scopeid: { type: "number" }, }, }, }, }, }), }); const textEncoder = new TextEncoder(); const INTERVAL_SEC = 0.5; let controller; server.on("subscribe", (_chanId) => { log("starting monitor"); if (controller) { controller.abort(); throw new Error("already running"); } controller = new AbortController(); void (async function (signal) { let lastStats; while (!signal.aborted) { const now = BigInt(Date.now()) * 1000000n; lastStats = getStats(lastStats); server.sendMessage(ch1, now, textEncoder.encode(JSON.stringify(lastStats))); await delay(INTERVAL_SEC); } })(controller.signal); }); server.on("unsubscribe", (_chanId) => { log("stopping monitor"); controller?.abort(); controller = undefined; }); server.on("error", (err) => { log("server error: %o", err); }); } exports.default = new commander_1.Command("sysmon") .description("publish CPU, memory, and network info") .action(main); //# sourceMappingURL=sysmon.js.map