mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-31 07:35:24 +00:00
feat: make each plugin an npm workspace built by a termix-plugin CLI
This commit is contained in:
1 parent
4758016f41
commit
5796186a1c
448 files changed
+3087
-2003
No files matched your search
@@ -0,0 +1,151 @@
|
||||
import type { Client } from "ssh2";
|
||||
import {
|
||||
execCommand,
|
||||
execPowerShell,
|
||||
toFixedNum,
|
||||
kibToGiB,
|
||||
type HostPlatform,
|
||||
} from "../../../../../src/backend/hosts/metrics-shared/common-utils.js";
|
||||
|
||||
async function collectDarwinMemoryMetrics(client: Client): Promise<{
|
||||
percent: number | null;
|
||||
usedGiB: number | null;
|
||||
totalGiB: number | null;
|
||||
}> {
|
||||
let memPercent: number | null = null;
|
||||
let usedGiB: number | null = null;
|
||||
let totalGiB: number | null = null;
|
||||
|
||||
try {
|
||||
const [vmStatOut, memSizeOut] = await Promise.all([
|
||||
execCommand(client, "vm_stat"),
|
||||
execCommand(client, "sysctl -n hw.memsize"),
|
||||
]);
|
||||
|
||||
const totalBytes = Number((memSizeOut.stdout || "").trim());
|
||||
const pageSizeMatch = vmStatOut.stdout.match(/page size of (\d+) bytes/);
|
||||
const pageSize = pageSizeMatch ? Number(pageSizeMatch[1]) : 4096;
|
||||
|
||||
const getPages = (key: string): number | null => {
|
||||
const line = vmStatOut.stdout
|
||||
.split("\n")
|
||||
.find((l) => l.trim().startsWith(key));
|
||||
if (!line) return null;
|
||||
const m = line.match(/(\d+)\./);
|
||||
return m ? Number(m[1]) : null;
|
||||
};
|
||||
|
||||
const active = getPages("Pages active");
|
||||
const wired = getPages("Pages wired down");
|
||||
const compressed = getPages("Pages occupied by compressor");
|
||||
|
||||
if (
|
||||
Number.isFinite(totalBytes) &&
|
||||
totalBytes > 0 &&
|
||||
active !== null &&
|
||||
wired !== null
|
||||
) {
|
||||
const usedPages = active + wired + (compressed ?? 0);
|
||||
const usedBytes = usedPages * pageSize;
|
||||
memPercent = Math.max(0, Math.min(100, (usedBytes / totalBytes) * 100));
|
||||
usedGiB = kibToGiB(usedBytes / 1024);
|
||||
totalGiB = kibToGiB(totalBytes / 1024);
|
||||
}
|
||||
} catch {
|
||||
memPercent = null;
|
||||
usedGiB = null;
|
||||
totalGiB = null;
|
||||
}
|
||||
|
||||
return {
|
||||
percent: toFixedNum(memPercent, 0),
|
||||
usedGiB: usedGiB ? toFixedNum(usedGiB, 2) : null,
|
||||
totalGiB: totalGiB ? toFixedNum(totalGiB, 2) : null,
|
||||
};
|
||||
}
|
||||
|
||||
// Win32_OperatingSystem reports TotalVisibleMemorySize/FreePhysicalMemory in KB.
|
||||
async function collectWindowsMemoryMetrics(client: Client): Promise<{
|
||||
percent: number | null;
|
||||
usedGiB: number | null;
|
||||
totalGiB: number | null;
|
||||
}> {
|
||||
let memPercent: number | null = null;
|
||||
let usedGiB: number | null = null;
|
||||
let totalGiB: number | null = null;
|
||||
|
||||
try {
|
||||
const { stdout } = await execPowerShell(
|
||||
client,
|
||||
"$os=Get-CimInstance Win32_OperatingSystem; [PSCustomObject]@{total=$os.TotalVisibleMemorySize; free=$os.FreePhysicalMemory} | ConvertTo-Json -Compress",
|
||||
);
|
||||
const parsed = JSON.parse(stdout.trim());
|
||||
const totalKb = Number(parsed?.total);
|
||||
const freeKb = Number(parsed?.free);
|
||||
if (Number.isFinite(totalKb) && Number.isFinite(freeKb) && totalKb > 0) {
|
||||
const usedKb = totalKb - freeKb;
|
||||
memPercent = Math.max(0, Math.min(100, (usedKb / totalKb) * 100));
|
||||
usedGiB = kibToGiB(usedKb);
|
||||
totalGiB = kibToGiB(totalKb);
|
||||
}
|
||||
} catch {
|
||||
memPercent = null;
|
||||
usedGiB = null;
|
||||
totalGiB = null;
|
||||
}
|
||||
|
||||
return {
|
||||
percent: toFixedNum(memPercent, 0),
|
||||
usedGiB: usedGiB ? toFixedNum(usedGiB, 2) : null,
|
||||
totalGiB: totalGiB ? toFixedNum(totalGiB, 2) : null,
|
||||
};
|
||||
}
|
||||
|
||||
export async function collectMemoryMetrics(
|
||||
client: Client,
|
||||
platform?: HostPlatform,
|
||||
): Promise<{
|
||||
percent: number | null;
|
||||
usedGiB: number | null;
|
||||
totalGiB: number | null;
|
||||
}> {
|
||||
if (platform === "darwin") {
|
||||
return collectDarwinMemoryMetrics(client);
|
||||
}
|
||||
if (platform === "windows") {
|
||||
return collectWindowsMemoryMetrics(client);
|
||||
}
|
||||
|
||||
let memPercent: number | null = null;
|
||||
let usedGiB: number | null = null;
|
||||
let totalGiB: number | null = null;
|
||||
|
||||
try {
|
||||
const memInfo = await execCommand(client, "cat /proc/meminfo");
|
||||
const lines = memInfo.stdout.split("\n");
|
||||
const getVal = (key: string) => {
|
||||
const line = lines.find((l) => l.startsWith(key));
|
||||
if (!line) return null;
|
||||
const m = line.match(/\d+/);
|
||||
return m ? Number(m[0]) : null;
|
||||
};
|
||||
const totalKb = getVal("MemTotal:");
|
||||
const availKb = getVal("MemAvailable:");
|
||||
if (totalKb && availKb && totalKb > 0) {
|
||||
const usedKb = totalKb - availKb;
|
||||
memPercent = Math.max(0, Math.min(100, (usedKb / totalKb) * 100));
|
||||
usedGiB = kibToGiB(usedKb);
|
||||
totalGiB = kibToGiB(totalKb);
|
||||
}
|
||||
} catch {
|
||||
memPercent = null;
|
||||
usedGiB = null;
|
||||
totalGiB = null;
|
||||
}
|
||||
|
||||
return {
|
||||
percent: toFixedNum(memPercent, 0),
|
||||
usedGiB: usedGiB ? toFixedNum(usedGiB, 2) : null,
|
||||
totalGiB: totalGiB ? toFixedNum(totalGiB, 2) : null,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user