/** * System Information * * Gathers CPU, RAM, disk, network, and GPU information */ import { runCommand } from '../utils/command.ts'; 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 { 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 { try { const result = await runCommand('hostname', []); if (!result.success) return 'unknown'; return result.stdout.trim(); } catch { return 'unknown'; } } private async getCpuInfo(): Promise { 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 { 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 { try { const result = await runCommand('df', ['-B1', '--output=source,target,size,used,avail']); if (!result.success) return []; const lines = result.stdout.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 { try { const cmdResult = await runCommand('ip', ['-j', 'addr']); if (!cmdResult.success) return []; const interfaces = JSON.parse(cmdResult.stdout); 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 { try { const result = await runCommand('lspci', ['-mm']); if (!result.success) return []; const lines = result.stdout.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 { try { const uptime = await Deno.readTextFile('/proc/uptime'); return Math.floor(parseFloat(uptime.split(' ')[0])); } catch { return 0; } } }