update
This commit is contained in:
231
ecoos_daemon/ts/daemon/system-info.ts
Normal file
231
ecoos_daemon/ts/daemon/system-info.ts
Normal file
@@ -0,0 +1,231 @@
|
||||
/**
|
||||
* System Information
|
||||
*
|
||||
* Gathers CPU, RAM, disk, network, and GPU information
|
||||
*/
|
||||
|
||||
export interface CpuInfo {
|
||||
model: string;
|
||||
cores: number;
|
||||
usage: number;
|
||||
}
|
||||
|
||||
export interface MemoryInfo {
|
||||
total: number;
|
||||
used: number;
|
||||
free: number;
|
||||
usagePercent: number;
|
||||
}
|
||||
|
||||
export interface DiskInfo {
|
||||
device: string;
|
||||
mountpoint: string;
|
||||
total: number;
|
||||
used: number;
|
||||
free: number;
|
||||
usagePercent: number;
|
||||
}
|
||||
|
||||
export interface NetworkInterface {
|
||||
name: string;
|
||||
ip: string;
|
||||
mac: string;
|
||||
state: 'up' | 'down';
|
||||
}
|
||||
|
||||
export interface GpuInfo {
|
||||
name: string;
|
||||
driver: string;
|
||||
}
|
||||
|
||||
export interface SystemInfoData {
|
||||
hostname: string;
|
||||
cpu: CpuInfo;
|
||||
memory: MemoryInfo;
|
||||
disks: DiskInfo[];
|
||||
network: NetworkInterface[];
|
||||
gpu: GpuInfo[];
|
||||
uptime: number;
|
||||
}
|
||||
|
||||
export class SystemInfo {
|
||||
async getInfo(): Promise<SystemInfoData> {
|
||||
const [hostname, cpu, memory, disks, network, gpu, uptime] =
|
||||
await Promise.all([
|
||||
this.getHostname(),
|
||||
this.getCpuInfo(),
|
||||
this.getMemoryInfo(),
|
||||
this.getDiskInfo(),
|
||||
this.getNetworkInfo(),
|
||||
this.getGpuInfo(),
|
||||
this.getUptime(),
|
||||
]);
|
||||
|
||||
return { hostname, cpu, memory, disks, network, gpu, uptime };
|
||||
}
|
||||
|
||||
private async getHostname(): Promise<string> {
|
||||
try {
|
||||
const result = await this.runCommand('hostname');
|
||||
return result.trim();
|
||||
} catch {
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
private async getCpuInfo(): Promise<CpuInfo> {
|
||||
try {
|
||||
const cpuinfo = await Deno.readTextFile('/proc/cpuinfo');
|
||||
const modelMatch = cpuinfo.match(/model name\s*:\s*(.+)/);
|
||||
const coreMatches = cpuinfo.match(/processor\s*:/g);
|
||||
|
||||
// Get CPU usage from /proc/stat
|
||||
const stat = await Deno.readTextFile('/proc/stat');
|
||||
const cpuLine = stat.split('\n')[0];
|
||||
const values = cpuLine.split(/\s+/).slice(1).map(Number);
|
||||
const total = values.reduce((a, b) => a + b, 0);
|
||||
const idle = values[3];
|
||||
const usage = ((total - idle) / total) * 100;
|
||||
|
||||
return {
|
||||
model: modelMatch ? modelMatch[1] : 'Unknown',
|
||||
cores: coreMatches ? coreMatches.length : 1,
|
||||
usage: Math.round(usage * 10) / 10,
|
||||
};
|
||||
} catch {
|
||||
return { model: 'Unknown', cores: 1, usage: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
private async getMemoryInfo(): Promise<MemoryInfo> {
|
||||
try {
|
||||
const meminfo = await Deno.readTextFile('/proc/meminfo');
|
||||
const totalMatch = meminfo.match(/MemTotal:\s*(\d+)/);
|
||||
const freeMatch = meminfo.match(/MemAvailable:\s*(\d+)/);
|
||||
|
||||
const total = totalMatch ? parseInt(totalMatch[1], 10) * 1024 : 0;
|
||||
const free = freeMatch ? parseInt(freeMatch[1], 10) * 1024 : 0;
|
||||
const used = total - free;
|
||||
|
||||
return {
|
||||
total,
|
||||
used,
|
||||
free,
|
||||
usagePercent: total > 0 ? Math.round((used / total) * 1000) / 10 : 0,
|
||||
};
|
||||
} catch {
|
||||
return { total: 0, used: 0, free: 0, usagePercent: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
private async getDiskInfo(): Promise<DiskInfo[]> {
|
||||
try {
|
||||
const output = await this.runCommand('df', ['-B1', '--output=source,target,size,used,avail']);
|
||||
const lines = output.trim().split('\n').slice(1);
|
||||
const disks: DiskInfo[] = [];
|
||||
|
||||
for (const line of lines) {
|
||||
const parts = line.trim().split(/\s+/);
|
||||
if (parts.length >= 5 && parts[0].startsWith('/dev/')) {
|
||||
const total = parseInt(parts[2], 10);
|
||||
const used = parseInt(parts[3], 10);
|
||||
const free = parseInt(parts[4], 10);
|
||||
|
||||
disks.push({
|
||||
device: parts[0],
|
||||
mountpoint: parts[1],
|
||||
total,
|
||||
used,
|
||||
free,
|
||||
usagePercent: total > 0 ? Math.round((used / total) * 1000) / 10 : 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return disks;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private async getNetworkInfo(): Promise<NetworkInterface[]> {
|
||||
try {
|
||||
const output = await this.runCommand('ip', ['-j', 'addr']);
|
||||
const interfaces = JSON.parse(output);
|
||||
const result: NetworkInterface[] = [];
|
||||
|
||||
for (const iface of interfaces) {
|
||||
if (iface.ifname === 'lo') continue;
|
||||
|
||||
let ip = '';
|
||||
let mac = iface.address || '';
|
||||
|
||||
for (const addr of iface.addr_info || []) {
|
||||
if (addr.family === 'inet') {
|
||||
ip = addr.local;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result.push({
|
||||
name: iface.ifname,
|
||||
ip: ip || 'No IP',
|
||||
mac,
|
||||
state: iface.operstate === 'UP' ? 'up' : 'down',
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private async getGpuInfo(): Promise<GpuInfo[]> {
|
||||
try {
|
||||
const output = await this.runCommand('lspci', ['-mm']);
|
||||
const lines = output.split('\n');
|
||||
const gpus: GpuInfo[] = [];
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.includes('VGA') || line.includes('3D') || line.includes('Display')) {
|
||||
const parts = line.split('"');
|
||||
if (parts.length >= 6) {
|
||||
gpus.push({
|
||||
name: parts[5] || 'Unknown GPU',
|
||||
driver: 'unknown',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gpus;
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private async getUptime(): Promise<number> {
|
||||
try {
|
||||
const uptime = await Deno.readTextFile('/proc/uptime');
|
||||
return Math.floor(parseFloat(uptime.split(' ')[0]));
|
||||
} catch {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private async runCommand(cmd: string, args: string[] = []): Promise<string> {
|
||||
const command = new Deno.Command(cmd, {
|
||||
args,
|
||||
stdout: 'piped',
|
||||
stderr: 'piped',
|
||||
});
|
||||
|
||||
const result = await command.output();
|
||||
if (!result.success) {
|
||||
throw new Error('Command failed');
|
||||
}
|
||||
|
||||
return new TextDecoder().decode(result.stdout);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user