UNPKG

node-os-utils

Version:

Advanced cross-platform operating system monitoring utilities with TypeScript support

1,144 lines 41.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MacOSAdapter = void 0; const os_1 = __importDefault(require("os")); const platform_adapter_1 = require("../core/platform-adapter"); const command_executor_1 = require("../utils/command-executor"); const errors_1 = require("../types/errors"); /** * macOS 平台适配器 * * 实现 macOS 系统的监控功能,主要通过 sysctl、vm_stat、system_profiler 等命令 */ class MacOSAdapter extends platform_adapter_1.BasePlatformAdapter { constructor() { super('darwin'); this.executor = new command_executor_1.CommandExecutor('darwin'); } /** * 执行系统命令 */ async executeCommand(command, options) { return this.executor.execute(command, options); } /** * 读取文件内容,捕获并转换常见的权限/不存在错误 */ async readFile(path) { try { const result = await this.executeCommand(`cat "${path}"`); this.validateCommandResult(result, `cat ${path}`); return result.stdout; } catch (error) { const err = error; const errorCode = err?.code === 'EACCES' ? errors_1.ErrorCode.PERMISSION_DENIED : err?.code === 'ENOENT' ? errors_1.ErrorCode.FILE_NOT_FOUND : errors_1.ErrorCode.COMMAND_FAILED; throw new errors_1.MonitorError(`Failed to read file: ${path}`, errorCode, this.platformName, { path, error: err?.message, code: err?.code }); } } /** * 检查文件是否存在 */ async fileExists(path) { try { const result = await this.executeCommand(`test -f "${path}"`); return result.exitCode === 0; } catch { return false; } } /** * 通过 sysctl 汇总 CPU 基本信息 */ async getCPUInfo() { try { const [brand, cores, threads, freq] = await Promise.allSettled([ this.executeCommand('sysctl -n machdep.cpu.brand_string'), this.executeCommand('sysctl -n hw.physicalcpu'), this.executeCommand('sysctl -n hw.logicalcpu'), this.executeCommand('sysctl -n hw.cpufrequency_max') ]).then(results => [ results[0].status === 'fulfilled' ? results[0].value : null, results[1].status === 'fulfilled' ? results[1].value : null, results[2].status === 'fulfilled' ? results[2].value : null, results[3].status === 'fulfilled' ? results[3].value : null ]); return this.parseCPUInfo(brand?.stdout || '', cores?.stdout || '', threads?.stdout || '', freq?.stdout || ''); } catch (error) { throw this.createCommandError('getCPUInfo', error); } } /** * 调用 top/iostat 获取 CPU 使用率,失败时链式回退 */ async getCPUUsage() { try { // 使用 top 命令获取 CPU 使用率 const result = await this.executeCommand('top -l 1 -n 0'); this.validateCommandResult(result, 'top command'); return this.parseCPUUsageFromTop(result.stdout); } catch (error) { // 回退到 iostat try { const result = await this.executeCommand('iostat -c 1'); this.validateCommandResult(result, 'iostat command'); return this.parseCPUUsageFromIostat(result.stdout); } catch { throw this.createCommandError('getCPUUsage', error); } } } /** * 使用 powermetrics 读取温度,需要 sudo 权限 */ async getCPUTemperature() { try { // macOS 温度监控需要第三方工具或私有 API // 尝试使用 powermetrics(需要 sudo) const result = await this.executeCommand('powermetrics -n 1 -i 1000 --samplers smc'); return this.parseTemperatureFromPowermetrics(result.stdout); } catch (error) { // 温度监控在 macOS 上可能需要额外权限 throw this.createUnsupportedError('cpu.temperature'); } } /** * 读取 vm_stat 解析内存占用 */ async getMemoryInfo() { try { const [vmStat, totalMem, pressure] = await Promise.allSettled([ this.executeCommand('vm_stat'), this.executeCommand('sysctl -n hw.memsize'), this.executeCommand('memory_pressure') ]).then(results => [ results[0].status === 'fulfilled' ? results[0].value : null, results[1].status === 'fulfilled' ? results[1].value : null, results[2].status === 'fulfilled' ? results[2].value : null ]); if (vmStat) this.validateCommandResult(vmStat, 'vm_stat'); if (totalMem) this.validateCommandResult(totalMem, 'sysctl hw.memsize'); return this.parseMemoryInfo(vmStat?.stdout || '', totalMem?.stdout || '', pressure?.stdout || ''); } catch (error) { throw this.createCommandError('getMemoryInfo', error); } } /** * 读取 vm_stat 解析内存占用 */ async getMemoryUsage() { // macOS 上内存信息和使用情况来自相同来源 return this.getMemoryInfo(); } /** * 读取 df -h 解析磁盘占用 */ async getDiskInfo() { try { const result = await this.executeCommand('df -h'); this.validateCommandResult(result, 'df -h'); return this.parseDiskInfo(result.stdout); } catch (error) { throw this.createCommandError('getDiskInfo', error); } } /** * 读取 iostat -d 解析磁盘 I/O 统计 */ async getDiskIO() { try { const result = await this.executeCommand('iostat -d'); this.validateCommandResult(result, 'iostat -d'); return this.parseDiskIO(result.stdout); } catch (error) { throw this.createCommandError('getDiskIO', error); } } /** * 读取 ifconfig 解析网络接口列表 */ async getNetworkInterfaces() { try { const result = await this.executeCommand('ifconfig'); this.validateCommandResult(result, 'ifconfig'); return this.parseNetworkInterfaces(result.stdout); } catch (error) { throw this.createCommandError('getNetworkInterfaces', error); } } /** * 读取 netstat -ib 解析网络统计信息 */ async getNetworkStats() { try { const result = await this.executeCommand('netstat -ib'); this.validateCommandResult(result, 'netstat -ib'); return this.parseNetworkStats(result.stdout); } catch (error) { throw this.createCommandError('getNetworkStats', error); } } /** * 读取 ps -axo pid=,ppid=,comm=,%cpu=,%mem=,rss=,stat=,user=,args= 解析进程列表 */ async getProcesses() { try { const result = await this.executeCommand('ps -axo pid=,ppid=,comm=,%cpu=,%mem=,rss=,stat=,user=,args='); this.validateCommandResult(result, 'ps command'); return this.parseProcessList(result.stdout); } catch (error) { throw this.createCommandError('getProcesses', error); } } /** * 读取 ps -p pid -o pid,ppid,command,pcpu,pmem,state,user,lstart 解析特定进程信息 */ async getProcessInfo(pid) { try { const [summaryResult, commandResult, startResult] = await Promise.all([ this.executeCommand(`ps -p ${pid} -o pid=,ppid=,rss=,pcpu=,pmem=,state=,user=`), this.executeCommand(`ps -p ${pid} -o command=`), this.executeCommand(`ps -p ${pid} -o lstart=`) ]); this.validateCommandResult(summaryResult, `ps summary ${pid}`); this.validateCommandResult(commandResult, `ps command ${pid}`); this.validateCommandResult(startResult, `ps lstart ${pid}`); const summaryLine = summaryResult.stdout.split('\n').find(line => line.trim().length > 0) || ''; const commandLine = commandResult.stdout.split('\n').find(line => line.trim().length > 0) || ''; const lstartLine = startResult.stdout.split('\n').find(line => line.trim().length > 0) || ''; return this.parseProcessInfo({ summary: summaryLine, command: commandLine, start: lstartLine }, pid); } catch (error) { throw this.createCommandError('getProcessInfo', error); } } /** * 读取 uname -a, uptime, sysctl -n vm.loadavg, sw_vers 解析系统信息 */ async getSystemInfo() { try { const [uname, uptime, loadavg, osVersion] = await Promise.allSettled([ this.executeCommand('uname -a'), this.executeCommand('uptime'), this.executeCommand('sysctl -n vm.loadavg'), this.executeCommand('sw_vers') ]).then(results => [ results[0].status === 'fulfilled' ? results[0].value : null, results[1].status === 'fulfilled' ? results[1].value : null, results[2].status === 'fulfilled' ? results[2].value : null, results[3].status === 'fulfilled' ? results[3].value : null ]); return this.parseSystemInfo(uname?.stdout || '', uptime?.stdout || '', loadavg?.stdout || '', osVersion?.stdout || null); } catch (error) { throw this.createCommandError('getSystemInfo', error); } } /** * 读取 sysctl -n vm.loadavg 解析系统负载 */ async getSystemLoad() { try { const result = await this.executeCommand('sysctl -n vm.loadavg'); this.validateCommandResult(result, 'sysctl vm.loadavg'); return this.parseLoadAverage(result.stdout); } catch (error) { throw this.createCommandError('getSystemLoad', error); } } /** * 读取 sysctl -n vm.loadavg 解析系统负载 */ initializeSupportedFeatures() { return { cpu: { info: true, usage: true, temperature: false, // 需要特殊权限 frequency: true, cache: false, perCore: false, cores: true }, memory: { info: true, usage: true, swap: true, pressure: true, detailed: true, virtual: true }, disk: { info: true, io: true, health: false, smart: false, filesystem: true, usage: true, stats: true, mounts: true, filesystems: true }, network: { interfaces: true, stats: true, connections: true, bandwidth: false, gateway: true }, process: { list: true, details: true, tree: false, monitor: true, info: true, kill: true, openFiles: true, environment: true }, system: { info: true, load: true, uptime: true, users: true, services: false } }; } // 私有解析方法,解析命令输出为结构化数据 parseCPUInfo(brand, cores, threads, freq) { return { model: brand.trim(), manufacturer: brand.includes('Intel') ? 'Intel' : brand.includes('Apple') ? 'Apple' : 'Unknown', architecture: 'Unknown', cores: this.safeParseInt(cores.trim()), threads: this.safeParseInt(threads.trim()), baseFrequency: freq ? this.safeParseInt(freq.trim()) / 1000000 : 0, // 转换为 MHz maxFrequency: freq ? this.safeParseInt(freq.trim()) / 1000000 : 0, cache: {}, features: [] }; } /** * 解析 top 命令输出为 CPU 使用率 */ parseCPUUsageFromTop(output) { const lines = output.split('\n'); const cpuLine = lines.find(line => line.includes('CPU usage:')); if (!cpuLine) { throw this.createParseError(output, 'CPU usage line not found in top output'); } // 解析类似 "CPU usage: 10.81% user, 13.73% sys, 75.45% idle" 的行 const userMatch = cpuLine.match(/([\d.]+)%\s+user/); const sysMatch = cpuLine.match(/([\d.]+)%\s+sys/); const idleMatch = cpuLine.match(/([\d.]+)%\s+idle/); const user = userMatch ? this.safeParseNumber(userMatch[1]) : 0; const system = sysMatch ? this.safeParseNumber(sysMatch[1]) : 0; const idle = idleMatch ? this.safeParseNumber(idleMatch[1]) : 0; return { overall: 100 - idle, user, system, idle, cores: [] }; } /** * 解析 iostat 命令输出为 CPU 使用率 */ parseCPUUsageFromIostat(output) { const lines = output.split('\n'); const dataLine = lines[lines.length - 2]; // iostat 的最后一行数据 if (!dataLine) { throw this.createParseError(output, 'No data line found in iostat output'); } const fields = dataLine.trim().split(/\s+/); if (fields.length >= 3) { const user = this.safeParseNumber(fields[0]); const system = this.safeParseNumber(fields[1]); const idle = this.safeParseNumber(fields[2]); return { overall: 100 - idle, user, system, idle, cores: [] }; } throw this.createParseError(output, 'Unable to parse iostat CPU data'); } /** * 解析 powermetrics 命令输出为温度 */ parseTemperatureFromPowermetrics(output) { // powermetrics 输出解析(简化版) const lines = output.split('\n'); const temperatures = []; for (const line of lines) { const tempMatch = line.match(/(\w+)\s+temperature:\s+([\d.]+)/); if (tempMatch) { temperatures.push({ sensor: tempMatch[1], temperature: this.safeParseNumber(tempMatch[2]) }); } } return temperatures; } /** * 解析 vm_stat 输出为内存信息 */ parseMemoryInfo(vmStat, totalMem, pressure) { const total = this.safeParseInt(totalMem.trim()); // 解析 vm_stat 输出 const vmLines = vmStat.split('\n'); const pageSizeLine = vmLines.find(line => /page size of\s+\d+\s+bytes/i.test(line)); const pageSizeMatch = pageSizeLine ? pageSizeLine.match(/page size of\s+(\d+)\s+bytes/i) : null; const detectedPageSize = pageSizeMatch && pageSizeMatch[1] ? this.safeParseInt(pageSizeMatch[1]) : 0; const pageSize = detectedPageSize > 0 ? detectedPageSize : 4096; let free = 0, active = 0, inactive = 0, wired = 0, compressed = 0; for (const line of vmLines) { const match = line.match(/Pages\s+([\w\s]+):\s+(\d+)/); if (match) { const [, typeRaw, count] = match; const type = typeRaw.trim().toLowerCase(); const bytes = this.safeParseInt(count) * pageSize; switch (type) { case 'free': free = bytes; break; case 'active': active = bytes; break; case 'inactive': inactive = bytes; break; case 'wired': case 'wired down': wired = bytes; break; case 'compressed': case 'occupied': case 'occupied by compressor': compressed = bytes; break; } } } const used = active + wired + compressed; const available = total - used; return { total, used, free, available, active, inactive, wired, compressed, usagePercentage: total > 0 ? (used / total) * 100 : 0, pressure: this.parseMemoryPressure(pressure) }; } /** * 解析 memory_pressure 输出为内存压力 */ parseMemoryPressure(pressure) { if (!pressure) { return { level: 'normal', score: 0 }; } // 简化的内存压力解析 if (pressure.includes('critical')) { return { level: 'critical', score: 90 }; } else if (pressure.includes('warn')) { return { level: 'high', score: 70 }; } else { return { level: 'normal', score: 10 }; } } /** * 解析 df -h 输出为磁盘信息 */ parseDiskInfo(output) { const lines = output.split('\n').filter(line => line.trim()); if (lines.length < 2) return []; const disks = []; for (let i = 1; i < lines.length; i++) { const fields = lines[i].split(/\s+/); if (fields.length >= 9) { const [filesystem, size, used, available, capacity, /* iused */ , /* ifree */ , /* iusedPercent */ , mountpoint] = fields; disks.push({ filesystem, mountpoint, size: this.convertDfSizeToBytes(size), used: this.convertDfSizeToBytes(used), available: this.convertDfSizeToBytes(available), usagePercentage: this.safeParseNumber(capacity.replace('%', '')) }); } } return disks; } /** * 解析 iostat -d 输出为磁盘 I/O 统计 */ parseDiskIO(output) { return this.parseIostatDisks(output).map(item => ({ device: item.device, kbPerTransfer: item.kbPerTransfer, transfersPerSec: item.transfersPerSec, mbPerSec: item.mbPerSec, readSpeed: item.bytePerSec, iops: item.transfersPerSec })); } /** * 解析 ifconfig 输出为网络接口列表 */ parseNetworkInterfaces(output) { const interfaces = []; const blocks = output.split(/\n(?=\w)/); // 按接口分割 for (const block of blocks) { const lines = block.split('\n'); const interfaceLine = lines[0]; if (!interfaceLine) continue; const nameMatch = interfaceLine.match(/^(\w+):/); if (!nameMatch) continue; const name = nameMatch[1]; const addresses = []; let state = 'down'; let mtu = 0; let macAddress = ''; for (const line of lines) { // 状态检查 if (line.includes('<UP,')) { state = 'up'; } // MTU 检查 const mtuMatch = line.match(/mtu (\d+)/); if (mtuMatch) { mtu = this.safeParseInt(mtuMatch[1]); } // MAC 地址 const etherMatch = line.match(/ether\s+([0-9a-f:]+)/i); if (etherMatch) { macAddress = etherMatch[1].toLowerCase(); } // IPv4 地址 const inetMatch = line.match(/inet\s+([^\s]+)/); if (inetMatch) { addresses.push({ address: inetMatch[1], family: 'IPv4' }); } // IPv6 地址 const inet6Match = line.match(/inet6\s+([^\s]+)/); if (inet6Match) { addresses.push({ address: inet6Match[1], family: 'IPv6' }); } } interfaces.push({ name, addresses, state, mtu, internal: name === 'lo0', mac: macAddress }); } return interfaces; } /** * 解析 netstat -ib/-i 输出,兼容是否包含字节列两种格式 */ parseNetworkStats(output) { const lines = output.split('\n').filter(line => line.trim()); if (lines.length === 0) return []; const header = lines[0].toLowerCase(); const stats = []; for (let i = 1; i < lines.length; i++) { const fields = lines[i].trim().split(/\s+/); if (fields.length < 8) continue; const name = fields[0]; const mtu = this.safeParseInt(fields[1]); if (header.includes('ibytes') && fields.length >= 11) { const tail = fields.slice(-7); if (tail.length < 7) continue; const [ipkts, ierrs, ibytes, opkts, oerrs, obytes, collisions] = tail; stats.push({ interface: name, mtu, rxPackets: this.safeParseInt(ipkts), rxErrors: this.safeParseInt(ierrs), rxBytes: this.safeParseInt(ibytes), txPackets: this.safeParseInt(opkts), txErrors: this.safeParseInt(oerrs), txBytes: this.safeParseInt(obytes), collisions: this.safeParseInt(collisions) }); continue; } const tail = fields.slice(-5); if (tail.length < 5) continue; const [ipkts, ierrs, opkts, oerrs, collisions] = tail; stats.push({ interface: name, mtu, rxPackets: this.safeParseInt(ipkts), rxErrors: this.safeParseInt(ierrs), rxBytes: 0, txPackets: this.safeParseInt(opkts), txErrors: this.safeParseInt(oerrs), txBytes: 0, collisions: this.safeParseInt(collisions) }); } return stats; } /** * 解析 ps -axo pid=,ppid=,comm=,%cpu=,%mem=,rss=,stat=,user=,args= 输出为进程列表 */ parseProcessList(output) { const lines = output.split('\n').filter(line => line.trim()); const processes = []; for (const line of lines) { const fields = line.trim().split(/\s+/); if (fields.length >= 8) { const [pid, ppid, cmd, pcpu, pmem, rss, state, user, ...argsParts] = fields; const command = argsParts.length > 0 ? argsParts.join(' ').trim() : cmd; processes.push({ pid: this.safeParseInt(pid), ppid: this.safeParseInt(ppid), name: cmd, comm: cmd, command, cpuUsage: this.safeParseNumber(pcpu), memoryUsage: this.safeParseInt(rss) * 1024, memoryPercentage: this.safeParseNumber(pmem), state, user }); } } return processes; } /** * 解析 ps 输出的进程详细信息 */ parseProcessInfo(data, pid) { const summaryParts = data.summary.trim().split(/\s+/); if (summaryParts.length < 7) { throw new errors_1.MonitorError(`Process ${pid} not found`, errors_1.ErrorCode.NOT_AVAILABLE, this.platformName, { pid }); } const [pidStr, ppidStr, rssStr, pcpu, pmem, state, user] = summaryParts; const command = data.command.trim(); const lstart = data.start.trim(); return { pid: this.safeParseInt(pidStr) || pid, ppid: this.safeParseInt(ppidStr), name: command.split(' ')[0] || command, command, cpuUsage: this.safeParseNumber(pcpu), memoryUsage: this.safeParseInt(rssStr) * 1024, memoryPercentage: this.safeParseNumber(pmem), state, user, startTime: lstart }; } /** * 解析 uname -a, uptime, sysctl -n vm.loadavg, sw_vers 输出为系统信息 */ parseSystemInfo(uname, uptime, loadavg, osVersion) { const unameFields = uname.trim().split(' '); const uptimeSeconds = os_1.default.uptime(); const bootTime = Date.now() - uptimeSeconds * 1000; const load = this.parseLoadAverage(loadavg); const uptimeMs = uptimeSeconds * 1000; return { hostname: unameFields[1] || 'Unknown', platform: 'darwin', release: unameFields[2] || 'Unknown', version: osVersion ? osVersion.trim() : unameFields[3] || 'Unknown', arch: unameFields[4] || 'Unknown', uptime: uptimeMs, uptimeSeconds, bootTime, loadAverage: load }; } /** * 解析 sysctl -n vm.loadavg 输出为系统负载 */ parseLoadAverage(output) { const match = output.trim().match(/\{\s*([\d.]+)\s+([\d.]+)\s+([\d.]+)\s*\}/); if (match) { return { load1: this.safeParseNumber(match[1]), load5: this.safeParseNumber(match[2]), load15: this.safeParseNumber(match[3]) }; } throw this.createParseError(output, 'Unable to parse load average'); } /** * 解析 df -h 输出的大小格式转换 */ convertDfSizeToBytes(sizeStr) { // df -h 输出的大小格式转换 const match = sizeStr.match(/^([\d.]+)([KMGT]?)i?$/); if (!match) return 0; const value = this.safeParseNumber(match[1]); const unit = match[2]; const multipliers = { '': 1024, // df 默认单位是 KB 'K': 1024, 'M': 1024 * 1024, 'G': 1024 * 1024 * 1024, 'T': 1024 * 1024 * 1024 * 1024 }; return value * (multipliers[unit] || 1024); } // 实现抽象方法,获取结构化数据 /** * 获取磁盘使用情况,解析 df -k 输出为磁盘使用情况 */ async getDiskUsage() { try { const result = await this.executeCommand('df -k'); return this.parseDiskUsage(result.stdout); } catch (error) { throw this.createCommandError('getDiskUsage', error); } } /** * 获取磁盘统计,解析 iostat -d 输出为磁盘统计 */ async getDiskStats() { try { const result = await this.executeCommand('iostat -d'); return this.parseDiskStats(result.stdout); } catch (error) { throw this.createCommandError('getDiskStats', error); } } /** * 获取挂载点,解析 mount 输出为挂载点 */ async getMounts() { try { const result = await this.executeCommand('mount'); return this.parseMounts(result.stdout); } catch (error) { throw this.createCommandError('getMounts', error); } } /** * 获取文件系统,解析 diskutil list 输出为文件系统 */ async getFileSystems() { try { const result = await this.executeCommand('diskutil list'); return this.parseFileSystems(result.stdout); } catch (error) { throw this.createCommandError('getFileSystems', error); } } /** * 获取网络连接,解析 netstat -an 输出为网络连接 */ async getNetworkConnections() { try { const result = await this.executeCommand('netstat -an'); return this.parseNetworkConnections(result.stdout); } catch (error) { throw this.createCommandError('getNetworkConnections', error); } } /** * 获取默认网关,解析 route -n get default 输出为默认网关 */ async getDefaultGateway() { try { const result = await this.executeCommand('route -n get default'); return this.parseDefaultGateway(result.stdout); } catch (error) { throw this.createCommandError('getDefaultGateway', error); } } /** * 获取进程列表,解析 ps -axo pid=,ppid=,comm=,%cpu=,%mem=,rss=,stat=,user=,args= 输出为进程列表 */ async getProcessList() { try { const result = await this.executeCommand('ps -axo pid=,ppid=,comm=,%cpu=,%mem=,rss=,stat=,user=,args='); return this.parseProcessList(result.stdout); } catch (error) { throw this.createCommandError('getProcessList', error); } } /** * 杀死进程,解析 kill -${signal} ${pid} 输出为杀死进程 */ async killProcess(pid, signal = 'TERM') { try { const result = await this.executeCommand(`kill -${signal} ${pid}`); return result.exitCode === 0; } catch (error) { return false; } } /** * 获取进程打开文件,解析 lsof -p ${pid} +c0 -Fn 输出为进程打开文件 */ async getProcessOpenFiles(pid) { try { const result = await this.executeCommand(`lsof -p ${pid} +c0 -Fn`); return this.parseOpenFiles(result.stdout); } catch (error) { return []; } } /** * 获取进程环境变量,解析 ps eww ${pid} 输出为进程环境变量 */ async getProcessEnvironment(pid) { try { const result = await this.executeCommand(`ps eww ${pid}`); return this.parseEnvironment(result.stdout); } catch (error) { return {}; } } /** * 获取系统运行时间 */ async getSystemUptime() { try { const uptimeSeconds = os_1.default.uptime(); return { uptime: uptimeSeconds, bootTime: Date.now() - uptimeSeconds * 1000 }; } catch (error) { throw this.createCommandError('getSystemUptime', error); } } /** * 获取系统用户,解析 who 输出为系统用户 */ async getSystemUsers() { try { const result = await this.executeCommand('who'); return this.parseSystemUsers(result.stdout); } catch (error) { throw this.createCommandError('getSystemUsers', error); } } /** * 获取系统服务,解析 launchctl list 输出为系统服务 */ async getSystemServices() { try { const result = await this.executeCommand('launchctl list'); return this.parseSystemServices(result.stdout); } catch (error) { throw this.createCommandError('getSystemServices', error); } } // 私有解析方法,解析命令输出为结构化数据 parseDiskUsage(output) { const lines = output.split('\n').slice(1); // 跳过标题行 const disks = []; for (const line of lines) { const fields = line.trim().split(/\s+/); if (fields.length >= 9) { const usedPercent = fields[4].replace('%', ''); disks.push({ device: fields[0], total: this.safeParseInt(fields[1]) * 1024, // KB to bytes used: this.safeParseInt(fields[2]) * 1024, available: this.safeParseInt(fields[3]) * 1024, usagePercentage: this.safeParseNumber(usedPercent), mountPoint: fields[8] }); } } return disks; } /** * 解析 iostat -d 输出为磁盘统计 */ parseDiskStats(output) { return this.parseIostatDisks(output).map(item => ({ device: item.device, readBytes: item.bytePerSec, writeBytes: 0, readCount: item.transfersPerSec, writeCount: 0, readTime: 0, writeTime: 0, ioTime: 0, readSpeed: item.bytePerSec, writeSpeed: 0, iops: item.transfersPerSec })); } /** * 解析 mount 输出为挂载点 */ parseMounts(output) { const lines = output.split('\n').filter(line => line.trim()); const mounts = []; for (const line of lines) { const match = line.match(/^(.+?)\s+on\s+(.+?)\s+\((.+?)\)$/); if (match) { const [, device, mountPoint, options] = match; const optionsArray = options.split(',').map(opt => opt.trim()); mounts.push({ device: device.trim(), mountPoint: mountPoint.trim(), filesystem: optionsArray[0] || 'unknown', options: optionsArray, dump: 0, pass: 0 }); } } return mounts; } /** * 解析 diskutil list 输出为文件系统 */ parseFileSystems(output) { const lines = output.split('\n').filter(line => line.trim()); const filesystems = []; for (const line of lines) { if (line.includes('GUID_partition_scheme') || line.includes('Apple_HFS') || line.includes('Apple_APFS') || line.includes('Microsoft Basic Data')) { const parts = line.trim().split(/\s+/); if (parts.length >= 3) { filesystems.push({ name: parts[2] || 'unknown', type: parts[1] || 'unknown', supported: true }); } } } return filesystems; } /** * 解析 netstat -an 输出为网络连接 */ parseNetworkConnections(output) { const lines = output.split('\n').filter(line => line.trim()); const connections = []; for (const line of lines) { const fields = line.trim().split(/\s+/); if (fields.length >= 6 && (fields[0].includes('tcp') || fields[0].includes('udp'))) { connections.push({ protocol: fields[0], localAddress: fields[3] || '*', foreignAddress: fields[4] || '*', state: fields[5] || 'unknown' }); } } return connections; } /** * 解析 route -n get default 输出为默认网关 */ parseDefaultGateway(output) { const lines = output.split('\n'); let gateway = null; let interfaceName = null; for (const line of lines) { if (line.includes('gateway:')) { const match = line.match(/gateway:\s*(.+)/); if (match) gateway = match[1].trim(); } if (line.includes('interface:')) { const match = line.match(/interface:\s*(.+)/); if (match) interfaceName = match[1].trim(); } } return gateway ? { gateway, interface: interfaceName || 'unknown' } : null; } /** * 解析 lsof -p ${pid} +c0 -Fn 输出为进程打开文件 */ parseOpenFiles(output) { const lines = output.split('\n'); const files = []; for (const line of lines) { if (line.startsWith('n')) { files.push(line.substring(1)); } } return files; } /** * 解析 ps eww ${pid} 输出为进程环境变量 */ parseEnvironment(output) { const env = {}; if (!output) { return env; } const pattern = /(^|\s)([A-Za-z_][A-Za-z0-9_]*)=([\s\S]*?)(?=(\s+[A-Za-z_][A-Za-z0-9_]*=)|$)/g; let match; while ((match = pattern.exec(output)) !== null) { const key = match[2]; if (key === 'PID') { continue; } const value = match[3].replace(/\s+$/u, ''); env[key] = value; } return env; } parseIostatDisks(output) { const lines = output.split('\n').map(line => line.trimEnd()); const deviceLineIndex = lines.findIndex(line => /disk\w+/i.test(line)); if (deviceLineIndex === -1) { return []; } const deviceLine = lines[deviceLineIndex]; const deviceNames = (deviceLine.match(/disk[^\s]*/gi) || []).map(name => name.trim()); if (deviceNames.length === 0) { return []; } const dataLines = lines.slice(deviceLineIndex + 1).filter(line => line && /[\d.]/.test(line)); if (dataLines.length === 0) { return []; } const tokens = dataLines[0].trim().split(/\s+/); const metricsPerDevice = 3; const result = []; deviceNames.forEach((device, index) => { const offset = index * metricsPerDevice; if (tokens.length >= offset + metricsPerDevice) { const kbPerTransfer = this.safeParseNumber(tokens[offset]); const transfersPerSec = this.safeParseNumber(tokens[offset + 1]); const mbPerSec = this.safeParseNumber(tokens[offset + 2]); const bytePerSec = mbPerSec * 1024 * 1024; result.push({ device, kbPerTransfer, transfersPerSec, mbPerSec, bytePerSec }); } }); return result; } /** * 解析 uptime 输出为系统运行时间 */ parseSystemUptime(output) { const uptimeMatch = output.match(/up\s+(.+?),/); const loadMatch = output.match(/load averages:\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)/); return { uptime: uptimeMatch ? uptimeMatch[1].trim() : 'unknown', loadAverage: loadMatch ? { load1: this.safeParseNumber(loadMatch[1]), load5: this.safeParseNumber(loadMatch[2]), load15: this.safeParseNumber(loadMatch[3]) } : { load1: 0, load5: 0, load15: 0 } }; } /** * 解析 who 输出为系统用户 */ parseSystemUsers(output) { const lines = output.split('\n').filter(line => line.trim()); const users = []; for (const line of lines) { const fields = line.trim().split(/\s+/); if (fields.length >= 5) { users.push({ user: fields[0], terminal: fields[1], loginTime: fields.slice(2, -1).join(' '), from: fields[fields.length - 1] }); } } return users; } /** * 解析 launchctl list 输出为系统服务 */ parseSystemServices(output) { const lines = output.split('\n').slice(1); // 跳过标题行 const services = []; for (const line of lines) { const fields = line.trim().split(/\s+/); if (fields.length >= 3) { services.push({ pid: fields[0] === '-' ? null : this.safeParseInt(fields[0]), status: fields[1], label: fields[2] }); } } return services; } } exports.MacOSAdapter = MacOSAdapter; //# sourceMappingURL=macos-adapter.js.map