node-os-utils 1.3.7 → 2.0.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/README.md +1113 -237
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/package.json +99 -0
  4. package/dist/src/adapters/adapter-factory.d.ts +87 -0
  5. package/dist/src/adapters/adapter-factory.d.ts.map +1 -0
  6. package/dist/src/adapters/adapter-factory.js +272 -0
  7. package/dist/src/adapters/adapter-factory.js.map +1 -0
  8. package/dist/src/adapters/linux-adapter.d.ts +199 -0
  9. package/dist/src/adapters/linux-adapter.d.ts.map +1 -0
  10. package/dist/src/adapters/linux-adapter.js +1308 -0
  11. package/dist/src/adapters/linux-adapter.js.map +1 -0
  12. package/dist/src/adapters/macos-adapter.d.ts +232 -0
  13. package/dist/src/adapters/macos-adapter.d.ts.map +1 -0
  14. package/dist/src/adapters/macos-adapter.js +1144 -0
  15. package/dist/src/adapters/macos-adapter.js.map +1 -0
  16. package/dist/src/adapters/windows-adapter.d.ts +124 -0
  17. package/dist/src/adapters/windows-adapter.d.ts.map +1 -0
  18. package/dist/src/adapters/windows-adapter.js +601 -0
  19. package/dist/src/adapters/windows-adapter.js.map +1 -0
  20. package/dist/src/core/base-monitor.d.ts +107 -0
  21. package/dist/src/core/base-monitor.d.ts.map +1 -0
  22. package/dist/src/core/base-monitor.js +312 -0
  23. package/dist/src/core/base-monitor.js.map +1 -0
  24. package/dist/src/core/cache-manager.d.ts +157 -0
  25. package/dist/src/core/cache-manager.d.ts.map +1 -0
  26. package/dist/src/core/cache-manager.js +315 -0
  27. package/dist/src/core/cache-manager.js.map +1 -0
  28. package/dist/src/core/platform-adapter.d.ts +197 -0
  29. package/dist/src/core/platform-adapter.d.ts.map +1 -0
  30. package/dist/src/core/platform-adapter.js +244 -0
  31. package/dist/src/core/platform-adapter.js.map +1 -0
  32. package/dist/src/index.d.ts +205 -0
  33. package/dist/src/index.d.ts.map +1 -0
  34. package/dist/src/index.js +315 -0
  35. package/dist/src/index.js.map +1 -0
  36. package/dist/src/monitors/cpu-monitor.d.ts +139 -0
  37. package/dist/src/monitors/cpu-monitor.d.ts.map +1 -0
  38. package/dist/src/monitors/cpu-monitor.js +433 -0
  39. package/dist/src/monitors/cpu-monitor.js.map +1 -0
  40. package/dist/src/monitors/disk-monitor.d.ts +136 -0
  41. package/dist/src/monitors/disk-monitor.d.ts.map +1 -0
  42. package/dist/src/monitors/disk-monitor.js +465 -0
  43. package/dist/src/monitors/disk-monitor.js.map +1 -0
  44. package/dist/src/monitors/memory-monitor.d.ts +136 -0
  45. package/dist/src/monitors/memory-monitor.d.ts.map +1 -0
  46. package/dist/src/monitors/memory-monitor.js +443 -0
  47. package/dist/src/monitors/memory-monitor.js.map +1 -0
  48. package/dist/src/monitors/network-monitor.d.ts +166 -0
  49. package/dist/src/monitors/network-monitor.d.ts.map +1 -0
  50. package/dist/src/monitors/network-monitor.js +586 -0
  51. package/dist/src/monitors/network-monitor.js.map +1 -0
  52. package/dist/src/monitors/process-monitor.d.ts +142 -0
  53. package/dist/src/monitors/process-monitor.d.ts.map +1 -0
  54. package/dist/src/monitors/process-monitor.js +460 -0
  55. package/dist/src/monitors/process-monitor.js.map +1 -0
  56. package/dist/src/monitors/system-monitor.d.ts +173 -0
  57. package/dist/src/monitors/system-monitor.d.ts.map +1 -0
  58. package/dist/src/monitors/system-monitor.js +592 -0
  59. package/dist/src/monitors/system-monitor.js.map +1 -0
  60. package/dist/src/types/common.d.ts +135 -0
  61. package/dist/src/types/common.d.ts.map +1 -0
  62. package/dist/src/types/common.js +141 -0
  63. package/dist/src/types/common.js.map +1 -0
  64. package/dist/src/types/config.d.ts +288 -0
  65. package/dist/src/types/config.d.ts.map +1 -0
  66. package/dist/src/types/config.js +3 -0
  67. package/dist/src/types/config.js.map +1 -0
  68. package/dist/src/types/errors.d.ts +40 -0
  69. package/dist/src/types/errors.d.ts.map +1 -0
  70. package/dist/src/types/errors.js +67 -0
  71. package/dist/src/types/errors.js.map +1 -0
  72. package/dist/src/types/index.d.ts +16 -0
  73. package/dist/src/types/index.d.ts.map +1 -0
  74. package/dist/src/types/index.js +36 -0
  75. package/dist/src/types/index.js.map +1 -0
  76. package/dist/src/types/monitors.d.ts +623 -0
  77. package/dist/src/types/monitors.d.ts.map +1 -0
  78. package/dist/src/types/monitors.js +3 -0
  79. package/dist/src/types/monitors.js.map +1 -0
  80. package/dist/src/types/platform.d.ts +435 -0
  81. package/dist/src/types/platform.d.ts.map +1 -0
  82. package/dist/src/types/platform.js +3 -0
  83. package/dist/src/types/platform.js.map +1 -0
  84. package/dist/src/utils/command-executor.d.ts +58 -0
  85. package/dist/src/utils/command-executor.d.ts.map +1 -0
  86. package/dist/src/utils/command-executor.js +321 -0
  87. package/dist/src/utils/command-executor.js.map +1 -0
  88. package/dist/test/config/test-config.d.ts +301 -0
  89. package/dist/test/config/test-config.d.ts.map +1 -0
  90. package/dist/test/config/test-config.js +235 -0
  91. package/dist/test/config/test-config.js.map +1 -0
  92. package/dist/test/platform/linux.test.d.ts +6 -0
  93. package/dist/test/platform/linux.test.d.ts.map +1 -0
  94. package/dist/test/platform/linux.test.js +307 -0
  95. package/dist/test/platform/linux.test.js.map +1 -0
  96. package/dist/test/platform/macos.test.d.ts +6 -0
  97. package/dist/test/platform/macos.test.d.ts.map +1 -0
  98. package/dist/test/platform/macos.test.js +276 -0
  99. package/dist/test/platform/macos.test.js.map +1 -0
  100. package/dist/test/platform/windows.test.d.ts +6 -0
  101. package/dist/test/platform/windows.test.d.ts.map +1 -0
  102. package/dist/test/platform/windows.test.js +320 -0
  103. package/dist/test/platform/windows.test.js.map +1 -0
  104. package/dist/test/unit/adapters/adapter-factory.test.d.ts +2 -0
  105. package/dist/test/unit/adapters/adapter-factory.test.d.ts.map +1 -0
  106. package/dist/test/unit/adapters/adapter-factory.test.js +147 -0
  107. package/dist/test/unit/adapters/adapter-factory.test.js.map +1 -0
  108. package/dist/test/unit/adapters/linux-adapter.test.d.ts +2 -0
  109. package/dist/test/unit/adapters/linux-adapter.test.d.ts.map +1 -0
  110. package/dist/test/unit/adapters/linux-adapter.test.js +191 -0
  111. package/dist/test/unit/adapters/linux-adapter.test.js.map +1 -0
  112. package/dist/test/unit/adapters/macos-adapter.test.d.ts +2 -0
  113. package/dist/test/unit/adapters/macos-adapter.test.d.ts.map +1 -0
  114. package/dist/test/unit/adapters/macos-adapter.test.js +224 -0
  115. package/dist/test/unit/adapters/macos-adapter.test.js.map +1 -0
  116. package/dist/test/unit/adapters/windows-adapter.test.d.ts +2 -0
  117. package/dist/test/unit/adapters/windows-adapter.test.d.ts.map +1 -0
  118. package/dist/test/unit/adapters/windows-adapter.test.js +41 -0
  119. package/dist/test/unit/adapters/windows-adapter.test.js.map +1 -0
  120. package/dist/test/unit/core/base-monitor.test.d.ts +2 -0
  121. package/dist/test/unit/core/base-monitor.test.d.ts.map +1 -0
  122. package/dist/test/unit/core/base-monitor.test.js +157 -0
  123. package/dist/test/unit/core/base-monitor.test.js.map +1 -0
  124. package/dist/test/unit/core/cache-manager.test.d.ts +6 -0
  125. package/dist/test/unit/core/cache-manager.test.d.ts.map +1 -0
  126. package/dist/test/unit/core/cache-manager.test.js +127 -0
  127. package/dist/test/unit/core/cache-manager.test.js.map +1 -0
  128. package/dist/test/unit/core/platform-adapter.test.d.ts +2 -0
  129. package/dist/test/unit/core/platform-adapter.test.d.ts.map +1 -0
  130. package/dist/test/unit/core/platform-adapter.test.js +186 -0
  131. package/dist/test/unit/core/platform-adapter.test.js.map +1 -0
  132. package/dist/test/unit/index.test.d.ts +2 -0
  133. package/dist/test/unit/index.test.d.ts.map +1 -0
  134. package/dist/test/unit/index.test.js +183 -0
  135. package/dist/test/unit/index.test.js.map +1 -0
  136. package/dist/test/unit/monitors/cpu-monitor.test.d.ts +2 -0
  137. package/dist/test/unit/monitors/cpu-monitor.test.d.ts.map +1 -0
  138. package/dist/test/unit/monitors/cpu-monitor.test.js +166 -0
  139. package/dist/test/unit/monitors/cpu-monitor.test.js.map +1 -0
  140. package/dist/test/unit/monitors/disk-monitor.test.d.ts +2 -0
  141. package/dist/test/unit/monitors/disk-monitor.test.d.ts.map +1 -0
  142. package/dist/test/unit/monitors/disk-monitor.test.js +46 -0
  143. package/dist/test/unit/monitors/disk-monitor.test.js.map +1 -0
  144. package/dist/test/unit/monitors/memory-monitor.test.d.ts +2 -0
  145. package/dist/test/unit/monitors/memory-monitor.test.d.ts.map +1 -0
  146. package/dist/test/unit/monitors/memory-monitor.test.js +142 -0
  147. package/dist/test/unit/monitors/memory-monitor.test.js.map +1 -0
  148. package/dist/test/unit/monitors/network-monitor.test.d.ts +2 -0
  149. package/dist/test/unit/monitors/network-monitor.test.d.ts.map +1 -0
  150. package/dist/test/unit/monitors/network-monitor.test.js +22 -0
  151. package/dist/test/unit/monitors/network-monitor.test.js.map +1 -0
  152. package/dist/test/unit/monitors/process-monitor.test.d.ts +2 -0
  153. package/dist/test/unit/monitors/process-monitor.test.d.ts.map +1 -0
  154. package/dist/test/unit/monitors/process-monitor.test.js +165 -0
  155. package/dist/test/unit/monitors/process-monitor.test.js.map +1 -0
  156. package/dist/test/unit/monitors/system-monitor-macos.test.d.ts +2 -0
  157. package/dist/test/unit/monitors/system-monitor-macos.test.d.ts.map +1 -0
  158. package/dist/test/unit/monitors/system-monitor-macos.test.js +115 -0
  159. package/dist/test/unit/monitors/system-monitor-macos.test.js.map +1 -0
  160. package/dist/test/unit/monitors/system-monitor.test.d.ts +2 -0
  161. package/dist/test/unit/monitors/system-monitor.test.d.ts.map +1 -0
  162. package/dist/test/unit/monitors/system-monitor.test.js +70 -0
  163. package/dist/test/unit/monitors/system-monitor.test.js.map +1 -0
  164. package/dist/test/unit/types/common.test.d.ts +6 -0
  165. package/dist/test/unit/types/common.test.d.ts.map +1 -0
  166. package/dist/test/unit/types/common.test.js +139 -0
  167. package/dist/test/unit/types/common.test.js.map +1 -0
  168. package/dist/test/unit/types/config.test.d.ts +2 -0
  169. package/dist/test/unit/types/config.test.d.ts.map +1 -0
  170. package/dist/test/unit/types/config.test.js +9 -0
  171. package/dist/test/unit/types/config.test.js.map +1 -0
  172. package/dist/test/unit/types/errors.test.d.ts +6 -0
  173. package/dist/test/unit/types/errors.test.d.ts.map +1 -0
  174. package/dist/test/unit/types/errors.test.js +184 -0
  175. package/dist/test/unit/types/errors.test.js.map +1 -0
  176. package/dist/test/unit/types/index.test.d.ts +2 -0
  177. package/dist/test/unit/types/index.test.d.ts.map +1 -0
  178. package/dist/test/unit/types/index.test.js +39 -0
  179. package/dist/test/unit/types/index.test.js.map +1 -0
  180. package/dist/test/unit/types/monitors.test.d.ts +2 -0
  181. package/dist/test/unit/types/monitors.test.d.ts.map +1 -0
  182. package/dist/test/unit/types/monitors.test.js +9 -0
  183. package/dist/test/unit/types/monitors.test.js.map +1 -0
  184. package/dist/test/unit/types/platform.test.d.ts +2 -0
  185. package/dist/test/unit/types/platform.test.d.ts.map +1 -0
  186. package/dist/test/unit/types/platform.test.js +9 -0
  187. package/dist/test/unit/types/platform.test.js.map +1 -0
  188. package/dist/test/unit/utils/command-executor.test.d.ts +6 -0
  189. package/dist/test/unit/utils/command-executor.test.d.ts.map +1 -0
  190. package/dist/test/unit/utils/command-executor.test.js +153 -0
  191. package/dist/test/unit/utils/command-executor.test.js.map +1 -0
  192. package/dist/test/unit/utils/platform-specific.test.d.ts +2 -0
  193. package/dist/test/unit/utils/platform-specific.test.d.ts.map +1 -0
  194. package/dist/test/unit/utils/platform-specific.test.js +32 -0
  195. package/dist/test/unit/utils/platform-specific.test.js.map +1 -0
  196. package/dist/test/utils/platform-specific.d.ts +139 -0
  197. package/dist/test/utils/platform-specific.d.ts.map +1 -0
  198. package/dist/test/utils/platform-specific.js +306 -0
  199. package/dist/test/utils/platform-specific.js.map +1 -0
  200. package/dist/test/utils/test-base.d.ts +157 -0
  201. package/dist/test/utils/test-base.d.ts.map +1 -0
  202. package/dist/test/utils/test-base.js +316 -0
  203. package/dist/test/utils/test-base.js.map +1 -0
  204. package/package.json +78 -18
  205. package/.travis.yml +0 -7
  206. package/index.js +0 -17
  207. package/lib/bucket.js +0 -14
  208. package/lib/cpu.js +0 -94
  209. package/lib/drive.js +0 -113
  210. package/lib/exec.js +0 -28
  211. package/lib/mem.js +0 -176
  212. package/lib/netstat.js +0 -182
  213. package/lib/openfiles.js +0 -25
  214. package/lib/os.js +0 -148
  215. package/lib/osCmd.js +0 -20
  216. package/lib/proc.js +0 -38
  217. package/lib/users.js +0 -18
  218. package/test/test.js +0 -55
  219. package/util/co.js +0 -237
  220. package/util/index.js +0 -12
@@ -0,0 +1,1308 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.LinuxAdapter = void 0;
30
+ const os_1 = __importDefault(require("os"));
31
+ const fs_1 = require("fs");
32
+ const fsSync = __importStar(require("fs"));
33
+ const platform_adapter_1 = require("../core/platform-adapter");
34
+ const command_executor_1 = require("../utils/command-executor");
35
+ const errors_1 = require("../types/errors");
36
+ /**
37
+ * Linux 平台适配器
38
+ *
39
+ * 实现 Linux 系统的监控功能,主要通过 /proc、/sys 文件系统和系统命令
40
+ */
41
+ class LinuxAdapter extends platform_adapter_1.BasePlatformAdapter {
42
+ constructor() {
43
+ super('linux');
44
+ this.processListCommand = 'ps -eo pid=,ppid=,comm=,%cpu=,%mem=,rss=,stat=,user=,args=';
45
+ this.cpuUsageSamplingInterval = 200;
46
+ // Linux 系统路径常量
47
+ this.paths = {
48
+ cpuinfo: '/proc/cpuinfo',
49
+ meminfo: '/proc/meminfo',
50
+ stat: '/proc/stat',
51
+ loadavg: '/proc/loadavg',
52
+ uptime: '/proc/uptime',
53
+ diskstats: '/proc/diskstats',
54
+ netDev: '/proc/net/dev',
55
+ version: '/proc/version',
56
+ mounts: '/proc/mounts',
57
+ thermal: '/sys/class/thermal',
58
+ cpufreq: '/sys/devices/system/cpu'
59
+ };
60
+ this.executor = new command_executor_1.CommandExecutor('linux');
61
+ this.containerMode = this.detectContainerEnvironment();
62
+ if (this.containerMode) {
63
+ this.supportedFeatures.system.services = false;
64
+ }
65
+ }
66
+ /**
67
+ * 执行系统命令
68
+ */
69
+ async executeCommand(command, options) {
70
+ return this.executor.execute(command, options);
71
+ }
72
+ /**
73
+ * 读取文件内容
74
+ */
75
+ async readFile(path) {
76
+ try {
77
+ return await fs_1.promises.readFile(path, 'utf8');
78
+ }
79
+ catch (error) {
80
+ if (error.code === 'ENOENT') {
81
+ throw new errors_1.MonitorError(`File not found: ${path}`, errors_1.ErrorCode.FILE_NOT_FOUND, this.platformName, { path });
82
+ }
83
+ if (error.code === 'EACCES') {
84
+ throw new errors_1.MonitorError(`Permission denied: ${path}`, errors_1.ErrorCode.PERMISSION_DENIED, this.platformName, { path });
85
+ }
86
+ throw new errors_1.MonitorError(`Failed to read file: ${path}`, errors_1.ErrorCode.COMMAND_FAILED, this.platformName, { path, error: error.message });
87
+ }
88
+ }
89
+ /**
90
+ * 检查文件是否存在
91
+ */
92
+ async fileExists(path) {
93
+ try {
94
+ await fs_1.promises.access(path);
95
+ return true;
96
+ }
97
+ catch {
98
+ return false;
99
+ }
100
+ }
101
+ /**
102
+ * 读取 /proc/cpuinfo 并解析成结构化 CPU 信息
103
+ */
104
+ async getCPUInfo() {
105
+ try {
106
+ const cpuinfoContent = await this.readFile(this.paths.cpuinfo);
107
+ return this.parseCPUInfo(cpuinfoContent);
108
+ }
109
+ catch (error) {
110
+ throw this.createCommandError('getCPUInfo', error);
111
+ }
112
+ }
113
+ /**
114
+ * 读取 /proc/stat,计算总体 CPU 使用情况
115
+ */
116
+ async getCPUUsage() {
117
+ try {
118
+ const firstSnapshot = await this.captureCpuStat();
119
+ await this.delay(this.cpuUsageSamplingInterval);
120
+ const secondSnapshot = await this.captureCpuStat();
121
+ return this.calculateCpuUsage(firstSnapshot, secondSnapshot);
122
+ }
123
+ catch (error) {
124
+ throw this.createCommandError('getCPUUsage', error);
125
+ }
126
+ }
127
+ /**
128
+ * 遍历 /sys/class/thermal,聚合 CPU 温度传感器
129
+ */
130
+ async getCPUTemperature() {
131
+ try {
132
+ const thermalExists = await this.fileExists(this.paths.thermal);
133
+ if (!thermalExists) {
134
+ throw this.createUnsupportedError('cpu.temperature');
135
+ }
136
+ // 尝试读取温度传感器
137
+ const thermalZones = await this.findThermalZones();
138
+ const temperatures = [];
139
+ for (const zone of thermalZones) {
140
+ try {
141
+ const tempPath = `${this.paths.thermal}/${zone}/temp`;
142
+ const tempContent = await this.readFile(tempPath);
143
+ let typeContent = 'unknown';
144
+ try {
145
+ typeContent = await this.readFile(`${this.paths.thermal}/${zone}/type`);
146
+ }
147
+ catch {
148
+ // 如果无法读取类型,使用默认值
149
+ }
150
+ const temp = this.safeParseInt(tempContent.trim()) / 1000; // 转换为摄氏度
151
+ temperatures.push({
152
+ zone,
153
+ type: typeContent.trim(),
154
+ temperature: temp
155
+ });
156
+ }
157
+ catch {
158
+ // 忽略无法读取的传感器
159
+ }
160
+ }
161
+ return temperatures;
162
+ }
163
+ catch (error) {
164
+ throw this.createCommandError('getCPUTemperature', error);
165
+ }
166
+ }
167
+ /**
168
+ * 读取 /proc/meminfo 解析内存占用
169
+ */
170
+ async getMemoryInfo() {
171
+ try {
172
+ const meminfoContent = await this.readFile(this.paths.meminfo);
173
+ return this.parseMemoryInfo(meminfoContent);
174
+ }
175
+ catch (error) {
176
+ throw this.createCommandError('getMemoryInfo', error);
177
+ }
178
+ }
179
+ /**
180
+ * 获取内存使用情况
181
+ */
182
+ async getMemoryUsage() {
183
+ // Linux 上内存信息和使用情况来自同一个文件
184
+ return this.getMemoryInfo();
185
+ }
186
+ /**
187
+ * 获取磁盘信息
188
+ */
189
+ async getDiskInfo() {
190
+ try {
191
+ const result = await this.executeCommand('df -h');
192
+ this.validateCommandResult(result, 'df -h');
193
+ return this.parseDiskInfo(result.stdout);
194
+ }
195
+ catch (error) {
196
+ throw this.createCommandError('getDiskInfo', error);
197
+ }
198
+ }
199
+ /**
200
+ * 获取磁盘 I/O 统计
201
+ */
202
+ async getDiskIO() {
203
+ try {
204
+ const diskstatsContent = await this.readFile(this.paths.diskstats);
205
+ return this.parseDiskStats(diskstatsContent);
206
+ }
207
+ catch (error) {
208
+ throw this.createCommandError('getDiskIO', error);
209
+ }
210
+ }
211
+ /**
212
+ * 获取网络接口列表
213
+ */
214
+ async getNetworkInterfaces() {
215
+ try {
216
+ const result = await this.executeCommand('ip addr show');
217
+ this.validateCommandResult(result, 'ip addr show');
218
+ return this.parseNetworkInterfaces(result.stdout);
219
+ }
220
+ catch (primaryError) {
221
+ // 回退到 ifconfig
222
+ try {
223
+ const result = await this.executeCommand('ifconfig');
224
+ this.validateCommandResult(result, 'ifconfig');
225
+ return this.parseIfconfigOutput(result.stdout);
226
+ }
227
+ catch (fallbackError) {
228
+ throw this.createCommandError('getNetworkInterfaces', {
229
+ primary: this.summarizeErrorDetails(primaryError),
230
+ fallback: this.summarizeErrorDetails(fallbackError)
231
+ });
232
+ }
233
+ }
234
+ }
235
+ /**
236
+ * 获取网络统计信息
237
+ */
238
+ async getNetworkStats() {
239
+ try {
240
+ const netdevContent = await this.readFile(this.paths.netDev);
241
+ return this.parseNetworkStats(netdevContent);
242
+ }
243
+ catch (error) {
244
+ throw this.createCommandError('getNetworkStats', error);
245
+ }
246
+ }
247
+ /**
248
+ * 获取进程列表
249
+ */
250
+ async getProcesses() {
251
+ try {
252
+ const result = await this.executeCommand(this.processListCommand);
253
+ this.validateCommandResult(result, 'ps command');
254
+ return this.parseProcessList(result.stdout);
255
+ }
256
+ catch (error) {
257
+ throw this.createCommandError('getProcesses', error);
258
+ }
259
+ }
260
+ /**
261
+ * 获取特定进程信息
262
+ */
263
+ async getProcessInfo(pid) {
264
+ try {
265
+ const procPath = `/proc/${pid}`;
266
+ const exists = await this.fileExists(procPath);
267
+ if (!exists) {
268
+ throw new errors_1.MonitorError(`Process ${pid} not found`, errors_1.ErrorCode.NOT_AVAILABLE, this.platformName, { pid });
269
+ }
270
+ const [stat, status, cmdline] = await Promise.allSettled([
271
+ this.readFile(`${procPath}/stat`),
272
+ this.readFile(`${procPath}/status`),
273
+ this.readFile(`${procPath}/cmdline`)
274
+ ]).then(results => [
275
+ results[0].status === 'fulfilled' ? results[0].value : '',
276
+ results[1].status === 'fulfilled' ? results[1].value : '',
277
+ results[2].status === 'fulfilled' ? results[2].value : ''
278
+ ]);
279
+ const statContent = stat || await this.readFile(`${procPath}/stat`).catch(() => '');
280
+ return this.parseProcessInfo(pid, statContent, status, cmdline);
281
+ }
282
+ catch (error) {
283
+ throw this.createCommandError('getProcessInfo', error);
284
+ }
285
+ }
286
+ /**
287
+ * 获取系统信息
288
+ */
289
+ async getSystemInfo() {
290
+ try {
291
+ const [uname, version, uptime, loadavg, machine] = await Promise.allSettled([
292
+ this.executeCommand('uname -a'),
293
+ this.readFile(this.paths.version),
294
+ this.readFile(this.paths.uptime),
295
+ this.readFile(this.paths.loadavg),
296
+ this.executeCommand('uname -m')
297
+ ]).then(results => [
298
+ results[0].status === 'fulfilled' ? results[0].value : null,
299
+ results[1].status === 'fulfilled' ? results[1].value : '',
300
+ results[2].status === 'fulfilled' ? results[2].value : '',
301
+ results[3].status === 'fulfilled' ? results[3].value : '',
302
+ results[4].status === 'fulfilled' ? results[4].value : null
303
+ ]);
304
+ const unameOutput = typeof uname === 'string' ? uname : uname?.stdout || '';
305
+ const versionOutput = typeof version === 'string' ? version : version?.stdout || '';
306
+ const uptimeOutput = typeof uptime === 'string' ? uptime : uptime?.stdout || '';
307
+ const loadavgOutput = typeof loadavg === 'string' ? loadavg : loadavg?.stdout || '';
308
+ const machineOutput = typeof machine === 'string' ? machine : machine?.stdout || '';
309
+ return this.parseSystemInfo(unameOutput, versionOutput, uptimeOutput, loadavgOutput, machineOutput);
310
+ }
311
+ catch (error) {
312
+ throw this.createCommandError('getSystemInfo', error);
313
+ }
314
+ }
315
+ /**
316
+ * 获取系统负载
317
+ */
318
+ async getSystemLoad() {
319
+ try {
320
+ const loadavgContent = await this.readFile(this.paths.loadavg);
321
+ return this.parseLoadAverage(loadavgContent);
322
+ }
323
+ catch (error) {
324
+ throw this.createCommandError('getSystemLoad', error);
325
+ }
326
+ }
327
+ /**
328
+ * 初始化支持的功能
329
+ */
330
+ initializeSupportedFeatures() {
331
+ return {
332
+ cpu: {
333
+ info: true,
334
+ usage: true,
335
+ temperature: true,
336
+ frequency: true,
337
+ cache: true,
338
+ perCore: true,
339
+ cores: true
340
+ },
341
+ memory: {
342
+ info: true,
343
+ usage: true,
344
+ swap: true,
345
+ pressure: false, // Linux 内存压力需要额外工具
346
+ detailed: true,
347
+ virtual: true
348
+ },
349
+ disk: {
350
+ info: true,
351
+ io: true,
352
+ health: false, // 需要 smartctl
353
+ smart: false,
354
+ filesystem: true,
355
+ usage: true,
356
+ stats: true,
357
+ mounts: true,
358
+ filesystems: true
359
+ },
360
+ network: {
361
+ interfaces: true,
362
+ stats: true,
363
+ connections: true,
364
+ bandwidth: true,
365
+ gateway: true
366
+ },
367
+ process: {
368
+ list: true,
369
+ details: true,
370
+ tree: true,
371
+ monitor: true,
372
+ info: true,
373
+ kill: true,
374
+ openFiles: true,
375
+ environment: true
376
+ },
377
+ system: {
378
+ info: true,
379
+ load: true,
380
+ uptime: true,
381
+ users: true,
382
+ services: false // 需要 systemctl
383
+ }
384
+ };
385
+ }
386
+ // 私有解析方法
387
+ parseCPUInfo(content) {
388
+ const lines = content.split('\n');
389
+ const cpus = [];
390
+ let currentCPU = {};
391
+ for (const line of lines) {
392
+ const trimmed = line.trim();
393
+ if (!trimmed) {
394
+ if (Object.keys(currentCPU).length > 0) {
395
+ cpus.push(currentCPU);
396
+ currentCPU = {};
397
+ }
398
+ continue;
399
+ }
400
+ const separatorIndex = trimmed.indexOf(':');
401
+ if (separatorIndex === -1)
402
+ continue;
403
+ const key = trimmed.substring(0, separatorIndex).trim();
404
+ const value = trimmed.substring(separatorIndex + 1).trim();
405
+ currentCPU[key] = value;
406
+ }
407
+ if (Object.keys(currentCPU).length > 0) {
408
+ cpus.push(currentCPU);
409
+ }
410
+ return {
411
+ cpus,
412
+ count: cpus.length,
413
+ model: cpus[0]?.['model name'] || 'Unknown',
414
+ vendor: cpus[0]?.['vendor_id'] || 'Unknown',
415
+ architecture: cpus[0]?.['cpu family'] || 'Unknown'
416
+ };
417
+ }
418
+ async captureCpuStat() {
419
+ const content = await this.readFile(this.paths.stat);
420
+ return this.parseCpuStat(content);
421
+ }
422
+ parseCpuStat(content) {
423
+ const lines = content
424
+ .split('\n')
425
+ .map(line => line.trim())
426
+ .filter(line => line.length > 0);
427
+ const summaryLine = lines.find(line => line.startsWith('cpu '));
428
+ if (!summaryLine) {
429
+ throw this.createParseError(content, 'CPU usage line not found');
430
+ }
431
+ const summary = this.parseCpuTimesFromLine(summaryLine);
432
+ const cores = [];
433
+ for (const line of lines) {
434
+ if (line.startsWith('cpu') && !line.startsWith('cpu ')) {
435
+ cores.push(this.parseCpuTimesFromLine(line));
436
+ }
437
+ }
438
+ return {
439
+ summary,
440
+ cores
441
+ };
442
+ }
443
+ parseCpuTimesFromLine(line) {
444
+ const parts = line.trim().split(/\s+/);
445
+ parts.shift(); // 移除 cpu 标识
446
+ const values = parts.map(value => this.safeParseInt(value));
447
+ return {
448
+ user: values[0] ?? 0,
449
+ nice: values[1] ?? 0,
450
+ system: values[2] ?? 0,
451
+ idle: values[3] ?? 0,
452
+ iowait: values[4] ?? 0,
453
+ irq: values[5] ?? 0,
454
+ softirq: values[6] ?? 0,
455
+ steal: values[7] ?? 0,
456
+ guest: values[8] ?? 0,
457
+ guestNice: values[9] ?? 0
458
+ };
459
+ }
460
+ calculateCpuUsage(previous, current) {
461
+ const summaryDelta = this.diffCpuTimes(previous.summary, current.summary);
462
+ const percentages = this.computeUsagePercentages(summaryDelta);
463
+ const cores = this.calculateCoreUsage(previous.cores, current.cores);
464
+ return {
465
+ overall: percentages.overall,
466
+ user: percentages.user,
467
+ system: percentages.system,
468
+ idle: percentages.idle,
469
+ iowait: percentages.iowait,
470
+ irq: percentages.irq,
471
+ softirq: percentages.softirq,
472
+ cores
473
+ };
474
+ }
475
+ calculateCoreUsage(previousCores, currentCores) {
476
+ const coreCount = Math.min(previousCores.length, currentCores.length);
477
+ const usages = [];
478
+ for (let i = 0; i < coreCount; i++) {
479
+ const delta = this.diffCpuTimes(previousCores[i], currentCores[i]);
480
+ const total = this.getCpuTotal(delta);
481
+ if (total <= 0) {
482
+ usages.push(0);
483
+ continue;
484
+ }
485
+ const busy = total - delta.idle;
486
+ usages.push((busy / total) * 100);
487
+ }
488
+ return usages;
489
+ }
490
+ diffCpuTimes(previous, current) {
491
+ return {
492
+ user: this.safeDiff(current.user, previous.user),
493
+ nice: this.safeDiff(current.nice, previous.nice),
494
+ system: this.safeDiff(current.system, previous.system),
495
+ idle: this.safeDiff(current.idle, previous.idle),
496
+ iowait: this.safeDiff(current.iowait, previous.iowait),
497
+ irq: this.safeDiff(current.irq, previous.irq),
498
+ softirq: this.safeDiff(current.softirq, previous.softirq),
499
+ steal: this.safeDiff(current.steal, previous.steal),
500
+ guest: this.safeDiff(current.guest, previous.guest),
501
+ guestNice: this.safeDiff(current.guestNice, previous.guestNice)
502
+ };
503
+ }
504
+ computeUsagePercentages(delta) {
505
+ const total = this.getCpuTotal(delta);
506
+ if (total <= 0) {
507
+ return {
508
+ overall: 0,
509
+ user: 0,
510
+ system: 0,
511
+ idle: 0,
512
+ iowait: 0,
513
+ irq: 0,
514
+ softirq: 0
515
+ };
516
+ }
517
+ return {
518
+ overall: ((total - delta.idle) / total) * 100,
519
+ user: ((delta.user + delta.nice) / total) * 100,
520
+ system: (delta.system / total) * 100,
521
+ idle: (delta.idle / total) * 100,
522
+ iowait: (delta.iowait / total) * 100,
523
+ irq: (delta.irq / total) * 100,
524
+ softirq: (delta.softirq / total) * 100
525
+ };
526
+ }
527
+ getCpuTotal(times) {
528
+ return times.user + times.nice + times.system + times.idle + times.iowait + times.irq + times.softirq + times.steal + times.guest + times.guestNice;
529
+ }
530
+ safeDiff(current, previous) {
531
+ const diff = current - previous;
532
+ return diff > 0 ? diff : 0;
533
+ }
534
+ parseMemoryInfo(content) {
535
+ const memInfo = this.parseKeyValueOutput(content);
536
+ const total = this.convertToBytes(memInfo['MemTotal'] || '0', 'kB');
537
+ const available = this.convertToBytes(memInfo['MemAvailable'] || memInfo['MemFree'] || '0', 'kB');
538
+ const free = this.convertToBytes(memInfo['MemFree'] || '0', 'kB');
539
+ const cached = this.convertToBytes(memInfo['Cached'] || '0', 'kB');
540
+ const buffers = this.convertToBytes(memInfo['Buffers'] || '0', 'kB');
541
+ const used = total - available;
542
+ return {
543
+ total,
544
+ available,
545
+ used,
546
+ free,
547
+ cached,
548
+ buffers,
549
+ usagePercentage: total > 0 ? (used / total) * 100 : 0,
550
+ swap: {
551
+ total: this.convertToBytes(memInfo['SwapTotal'] || '0', 'kB'),
552
+ free: this.convertToBytes(memInfo['SwapFree'] || '0', 'kB'),
553
+ used: this.convertToBytes(memInfo['SwapTotal'] || '0', 'kB') - this.convertToBytes(memInfo['SwapFree'] || '0', 'kB')
554
+ }
555
+ };
556
+ }
557
+ parseDiskInfo(output) {
558
+ const lines = output.split('\n').filter(line => line.trim());
559
+ if (lines.length < 2)
560
+ return [];
561
+ const disks = [];
562
+ for (let i = 1; i < lines.length; i++) {
563
+ const fields = lines[i].split(/\s+/);
564
+ if (fields.length >= 6) {
565
+ const [filesystem, size, used, available, usagePercent, mountpoint] = fields;
566
+ disks.push({
567
+ filesystem,
568
+ mountpoint,
569
+ size: this.convertToBytes(size),
570
+ used: this.convertToBytes(used),
571
+ available: this.convertToBytes(available),
572
+ usagePercentage: this.safeParseNumber(usagePercent.replace('%', ''))
573
+ });
574
+ }
575
+ }
576
+ return disks;
577
+ }
578
+ /**
579
+ * 解析 ip/ifconfig 输出的网卡信息,稳定提取接口名称
580
+ */
581
+ parseNetworkInterfaces(output) {
582
+ const interfaces = [];
583
+ const lines = output.split('\n');
584
+ let current = null;
585
+ const pushCurrent = () => {
586
+ if (current) {
587
+ interfaces.push({
588
+ name: current.name,
589
+ addresses: current.addresses,
590
+ state: current.state,
591
+ mtu: current.mtu,
592
+ internal: current.internal || current.loopbackDetected
593
+ });
594
+ }
595
+ current = null;
596
+ };
597
+ for (const rawLine of lines) {
598
+ const headerMatch = rawLine.match(/^\s*(\d+):\s*([^:@]+)(?:@[^:]+)?:\s*(.*)$/);
599
+ if (headerMatch) {
600
+ pushCurrent();
601
+ const name = headerMatch[2];
602
+ const rest = headerMatch[3] || '';
603
+ const stateMatch = rest.match(/\bstate\s+([A-Z]+)/i);
604
+ const mtuMatch = rest.match(/\bmtu\s+(\d+)/i);
605
+ const isLoopback = /\bLOOPBACK\b/i.test(rest);
606
+ current = {
607
+ name,
608
+ addresses: [],
609
+ state: stateMatch ? stateMatch[1].toLowerCase() : 'down',
610
+ mtu: mtuMatch ? this.safeParseInt(mtuMatch[1]) : 0,
611
+ internal: name === 'lo' || name === 'lo0',
612
+ loopbackDetected: isLoopback
613
+ };
614
+ continue;
615
+ }
616
+ if (!current) {
617
+ continue;
618
+ }
619
+ const line = rawLine.trim();
620
+ if (!line) {
621
+ continue;
622
+ }
623
+ if (/loopback/i.test(line)) {
624
+ current.loopbackDetected = true;
625
+ }
626
+ const inetMatch = line.match(/^inet\s+([^\s/]+)(?:\/\d+)?/);
627
+ if (inetMatch) {
628
+ current.addresses.push({
629
+ address: inetMatch[1],
630
+ family: 'IPv4'
631
+ });
632
+ continue;
633
+ }
634
+ const inet6Match = line.match(/^inet6\s+([^\s/]+)(?:\/\d+)?/);
635
+ if (inet6Match) {
636
+ current.addresses.push({
637
+ address: inet6Match[1],
638
+ family: 'IPv6'
639
+ });
640
+ }
641
+ }
642
+ pushCurrent();
643
+ return interfaces;
644
+ }
645
+ parseIfconfigOutput(output) {
646
+ // 解析 ifconfig 输出的简化版本
647
+ const interfaces = [];
648
+ const blocks = output.split(/\n\n/);
649
+ for (const block of blocks) {
650
+ const lines = block.split('\n');
651
+ const interfaceLine = lines[0];
652
+ if (!interfaceLine)
653
+ continue;
654
+ const nameMatch = interfaceLine.match(/^(\w+):/);
655
+ if (!nameMatch)
656
+ continue;
657
+ const name = nameMatch[1];
658
+ const addresses = [];
659
+ for (const line of lines) {
660
+ const inetMatch = line.match(/inet\s+([^\s]+)/);
661
+ if (inetMatch) {
662
+ addresses.push({
663
+ address: inetMatch[1],
664
+ family: 'IPv4'
665
+ });
666
+ }
667
+ }
668
+ interfaces.push({
669
+ name,
670
+ addresses,
671
+ state: interfaceLine.includes('UP') ? 'up' : 'down'
672
+ });
673
+ }
674
+ return interfaces;
675
+ }
676
+ /**
677
+ * 解析 /proc/net/dev 网络统计数据
678
+ *
679
+ * 将原始列按接口拆分,并提取收发字节/错误/丢包等指标
680
+ */
681
+ parseNetworkStats(content) {
682
+ const lines = content.split('\n');
683
+ const stats = [];
684
+ for (let i = 2; i < lines.length; i++) { // 跳过头部
685
+ const line = lines[i].trim();
686
+ if (!line)
687
+ continue;
688
+ const fields = line.split(/\s+/);
689
+ if (fields.length >= 17) {
690
+ const [iface, ...values] = fields;
691
+ const name = iface.replace(':', '');
692
+ stats.push({
693
+ interface: name,
694
+ rxBytes: this.safeParseInt(values[0]),
695
+ rxPackets: this.safeParseInt(values[1]),
696
+ rxErrors: this.safeParseInt(values[2]),
697
+ rxDropped: this.safeParseInt(values[3]),
698
+ txBytes: this.safeParseInt(values[8]),
699
+ txPackets: this.safeParseInt(values[9]),
700
+ txErrors: this.safeParseInt(values[10]),
701
+ txDropped: this.safeParseInt(values[11])
702
+ });
703
+ }
704
+ }
705
+ return stats;
706
+ }
707
+ parseProcessList(output) {
708
+ const lines = output.split('\n').filter(line => line.trim());
709
+ const processes = [];
710
+ for (const line of lines) {
711
+ const match = line.match(/^(\d+)\s+(\d+)\s+(\S+)\s+([\d.]+)\s+([\d.]+)\s+(\d+)\s+(\S+)\s+(\S+)\s*(.*)$/);
712
+ if (!match) {
713
+ continue;
714
+ }
715
+ const [, pid, ppid, comm, pcpu, pmem, rss, state, user, args] = match;
716
+ const command = args.trim() || comm;
717
+ processes.push({
718
+ pid: this.safeParseInt(pid),
719
+ ppid: this.safeParseInt(ppid),
720
+ name: comm,
721
+ command,
722
+ cpuUsage: this.safeParseNumber(pcpu),
723
+ memoryUsage: this.safeParseInt(rss) * 1024, // rss 以 KB 计,转换为字节
724
+ memoryPercentage: this.safeParseNumber(pmem),
725
+ state,
726
+ user
727
+ });
728
+ }
729
+ return processes;
730
+ }
731
+ /**
732
+ * 综合 /proc/[pid] 下多份文件,拼装进程详细信息
733
+ */
734
+ parseProcessInfo(pid, stat, status, cmdline) {
735
+ const statusInfo = this.parseKeyValueOutput(status, '\t');
736
+ const statFields = stat.split(' ');
737
+ const startTimeTicks = this.safeParseInt(statFields[21]);
738
+ const sysconf = os_1.default.constants?.sysconf;
739
+ const hertz = typeof sysconf?.SC_CLK_TCK === 'number' && sysconf.SC_CLK_TCK > 0
740
+ ? sysconf.SC_CLK_TCK
741
+ : 100;
742
+ let uptimeMs = 0;
743
+ try {
744
+ uptimeMs = os_1.default.uptime() * 1000;
745
+ }
746
+ catch {
747
+ uptimeMs = 0;
748
+ }
749
+ const bootTimeMs = uptimeMs > 0 ? Date.now() - uptimeMs : Date.now();
750
+ // 通过时钟节拍 + 开机时间估算进程启动时间,兼容无法访问 uptime 的环境
751
+ const computedStartTime = startTimeTicks > 0
752
+ ? bootTimeMs + (startTimeTicks / hertz) * 1000
753
+ : bootTimeMs;
754
+ const startTime = Math.min(computedStartTime, Date.now());
755
+ const rssPages = this.safeParseInt(statFields[23]);
756
+ const pageSize = typeof sysconf?.SC_PAGESIZE === 'number' && sysconf.SC_PAGESIZE > 0
757
+ ? sysconf.SC_PAGESIZE
758
+ : 4096;
759
+ const rssBytesFromStat = rssPages > 0 ? rssPages * pageSize : 0;
760
+ const vmRssRaw = statusInfo['VmRSS'] ?? statusInfo['VmRSS:'] ?? '0';
761
+ const vmSizeRaw = statusInfo['VmSize'] ?? statusInfo['VmSize:'] ?? '0';
762
+ const threadsRaw = statusInfo['Threads'] ?? statusInfo['Threads:'];
763
+ // 优先使用 /proc/[pid]/status 中的 KiB 数值,缺失时回退到 stat 的页数
764
+ const rssFromStatus = this.convertToBytes(vmRssRaw, 'kB');
765
+ const memoryUsage = rssFromStatus > 0 ? rssFromStatus : rssBytesFromStat;
766
+ return {
767
+ pid,
768
+ name: statusInfo['Name'] || 'Unknown',
769
+ command: cmdline.replace(/\0/g, ' ').trim(),
770
+ state: statFields[2] || 'Unknown',
771
+ ppid: this.safeParseInt(statFields[3]),
772
+ threads: this.safeParseInt(threadsRaw),
773
+ vmSize: this.convertToBytes(vmSizeRaw, 'kB'),
774
+ vmRSS: memoryUsage,
775
+ memoryUsage,
776
+ memory: memoryUsage,
777
+ rss: memoryUsage,
778
+ startTime
779
+ };
780
+ }
781
+ parseSystemInfo(uname, version, uptime, loadavg, machine) {
782
+ const unameFields = uname.trim().split(' ');
783
+ const uptimeFields = uptime.trim().split(' ');
784
+ const loadFields = loadavg.trim().split(' ');
785
+ const uptimeSeconds = this.safeParseNumber(uptimeFields[0]);
786
+ const uptimeMs = uptimeSeconds * 1000;
787
+ const bootTime = Date.now() - uptimeMs;
788
+ const architecture = this.resolveArchitecture(unameFields, machine);
789
+ return {
790
+ hostname: unameFields[1] || 'Unknown',
791
+ platform: 'linux', // 统一返回标准平台名称,与 os.platform() 保持一致
792
+ release: unameFields[2] || 'Unknown',
793
+ version: version.trim(),
794
+ arch: architecture,
795
+ uptime: uptimeMs,
796
+ uptimeSeconds,
797
+ bootTime,
798
+ loadAverage: {
799
+ load1: this.safeParseNumber(loadFields[0]),
800
+ load5: this.safeParseNumber(loadFields[1]),
801
+ load15: this.safeParseNumber(loadFields[2])
802
+ }
803
+ };
804
+ }
805
+ parseLoadAverage(content) {
806
+ const fields = content.trim().split(' ');
807
+ return {
808
+ load1: this.safeParseNumber(fields[0]),
809
+ load5: this.safeParseNumber(fields[1]),
810
+ load15: this.safeParseNumber(fields[2]),
811
+ processes: {
812
+ active: this.safeParseInt(fields[3]?.split('/')[0]),
813
+ total: this.safeParseInt(fields[3]?.split('/')[1])
814
+ }
815
+ };
816
+ }
817
+ async findThermalZones() {
818
+ try {
819
+ const items = await fs_1.promises.readdir(this.paths.thermal);
820
+ return items.filter(item => item.startsWith('thermal_zone'));
821
+ }
822
+ catch {
823
+ return [];
824
+ }
825
+ }
826
+ // 实现抽象方法
827
+ /**
828
+ * 获取磁盘使用情况
829
+ */
830
+ async getDiskUsage() {
831
+ try {
832
+ const result = await this.executeCommand('df -B1');
833
+ return this.parseDiskUsage(result.stdout);
834
+ }
835
+ catch (error) {
836
+ throw this.createCommandError('getDiskUsage', error);
837
+ }
838
+ }
839
+ /**
840
+ * 获取磁盘统计
841
+ */
842
+ async getDiskStats() {
843
+ try {
844
+ const diskstatsContent = await this.readFile(this.paths.diskstats);
845
+ return this.parseDiskStats(diskstatsContent);
846
+ }
847
+ catch (error) {
848
+ throw this.createCommandError('getDiskStats', error);
849
+ }
850
+ }
851
+ /**
852
+ * 获取挂载点
853
+ */
854
+ async getMounts() {
855
+ try {
856
+ const mountsContent = await this.readFile(this.paths.mounts);
857
+ return this.parseMounts(mountsContent);
858
+ }
859
+ catch (error) {
860
+ throw this.createCommandError('getMounts', error);
861
+ }
862
+ }
863
+ /**
864
+ * 获取文件系统
865
+ */
866
+ async getFileSystems() {
867
+ try {
868
+ const result = await this.executeCommand('cat /proc/filesystems');
869
+ return this.parseFileSystems(result.stdout);
870
+ }
871
+ catch (error) {
872
+ throw this.createCommandError('getFileSystems', error);
873
+ }
874
+ }
875
+ /**
876
+ * 获取网络连接
877
+ */
878
+ async getNetworkConnections() {
879
+ try {
880
+ const result = await this.executeCommand('ss -tuln');
881
+ return this.parseNetworkConnections(result.stdout);
882
+ }
883
+ catch (primaryError) {
884
+ try {
885
+ const result = await this.executeCommand('netstat -tuln');
886
+ this.validateCommandResult(result, 'netstat -tuln');
887
+ return this.parseNetstatConnections(result.stdout);
888
+ }
889
+ catch (fallbackError) {
890
+ throw this.createCommandError('getNetworkConnections', {
891
+ primary: this.summarizeErrorDetails(primaryError),
892
+ fallback: this.summarizeErrorDetails(fallbackError)
893
+ });
894
+ }
895
+ }
896
+ }
897
+ /**
898
+ * 获取默认网关
899
+ */
900
+ async getDefaultGateway() {
901
+ try {
902
+ const result = await this.executeCommand('ip route show default');
903
+ return this.parseDefaultGateway(result.stdout);
904
+ }
905
+ catch (error) {
906
+ throw this.createCommandError('getDefaultGateway', error);
907
+ }
908
+ }
909
+ /**
910
+ * 获取进程列表
911
+ */
912
+ async getProcessList() {
913
+ try {
914
+ const result = await this.executeCommand(this.processListCommand);
915
+ this.validateCommandResult(result, 'ps command');
916
+ return this.parseProcessList(result.stdout);
917
+ }
918
+ catch (error) {
919
+ throw this.createCommandError('getProcessList', error);
920
+ }
921
+ }
922
+ /**
923
+ * 杀死进程
924
+ */
925
+ async killProcess(pid, signal = 'TERM') {
926
+ try {
927
+ const result = await this.executeCommand(`kill -${signal} ${pid}`);
928
+ return result.exitCode === 0;
929
+ }
930
+ catch (error) {
931
+ return false;
932
+ }
933
+ }
934
+ /**
935
+ * 获取进程打开文件
936
+ */
937
+ async getProcessOpenFiles(pid) {
938
+ try {
939
+ const result = await this.executeCommand(`lsof -p ${pid} -Fn`);
940
+ return this.parseOpenFiles(result.stdout);
941
+ }
942
+ catch (error) {
943
+ return [];
944
+ }
945
+ }
946
+ /**
947
+ * 获取进程环境变量
948
+ */
949
+ async getProcessEnvironment(pid) {
950
+ try {
951
+ const environContent = await this.readFile(`/proc/${pid}/environ`);
952
+ return this.parseEnvironment(environContent);
953
+ }
954
+ catch (error) {
955
+ return {};
956
+ }
957
+ }
958
+ /**
959
+ * 获取系统运行时间
960
+ */
961
+ async getSystemUptime() {
962
+ try {
963
+ const uptimeContent = await this.readFile(this.paths.uptime);
964
+ const uptimeFields = uptimeContent.trim().split(' ');
965
+ return {
966
+ uptime: this.safeParseNumber(uptimeFields[0]) * 1000, // 转换为毫秒
967
+ idleTime: this.safeParseNumber(uptimeFields[1]) * 1000 // 转换为毫秒
968
+ };
969
+ }
970
+ catch (error) {
971
+ throw this.createCommandError('getSystemUptime', error);
972
+ }
973
+ }
974
+ /**
975
+ * 获取系统用户
976
+ */
977
+ async getSystemUsers() {
978
+ try {
979
+ const result = await this.executeCommand('who');
980
+ return this.parseSystemUsers(result.stdout);
981
+ }
982
+ catch (error) {
983
+ throw this.createCommandError('getSystemUsers', error);
984
+ }
985
+ }
986
+ /**
987
+ * 获取系统服务
988
+ */
989
+ async getSystemServices() {
990
+ if (this.containerMode) {
991
+ throw this.createUnsupportedError('system.services (container)');
992
+ }
993
+ try {
994
+ const result = await this.executeCommand('systemctl list-units --type=service --no-pager');
995
+ return this.parseSystemServices(result.stdout);
996
+ }
997
+ catch (error) {
998
+ throw this.createCommandError('getSystemServices', error);
999
+ }
1000
+ }
1001
+ // 私有解析方法
1002
+ parseDiskUsage(output) {
1003
+ const lines = output.split('\n').slice(1); // 跳过标题行
1004
+ const disks = [];
1005
+ for (const line of lines) {
1006
+ const fields = line.trim().split(/\s+/);
1007
+ if (fields.length >= 6) {
1008
+ disks.push({
1009
+ device: fields[0],
1010
+ total: this.safeParseInt(fields[1]),
1011
+ used: this.safeParseInt(fields[2]),
1012
+ available: this.safeParseInt(fields[3]),
1013
+ usagePercentage: this.safeParseNumber(fields[4].replace('%', '')),
1014
+ mountPoint: fields[5]
1015
+ });
1016
+ }
1017
+ }
1018
+ return disks;
1019
+ }
1020
+ parseDiskStats(content) {
1021
+ const lines = content.split('\n').filter(line => line.trim());
1022
+ const stats = [];
1023
+ for (const line of lines) {
1024
+ const fields = line.trim().split(/\s+/);
1025
+ if (fields.length >= 14) {
1026
+ stats.push({
1027
+ device: fields[2],
1028
+ reads: this.safeParseInt(fields[3]),
1029
+ readsMerged: this.safeParseInt(fields[4]),
1030
+ readSectors: this.safeParseInt(fields[5]),
1031
+ readTime: this.safeParseInt(fields[6]),
1032
+ writes: this.safeParseInt(fields[7]),
1033
+ writesMerged: this.safeParseInt(fields[8]),
1034
+ writeSectors: this.safeParseInt(fields[9]),
1035
+ writeTime: this.safeParseInt(fields[10]),
1036
+ ioInProgress: this.safeParseInt(fields[11]),
1037
+ ioTime: this.safeParseInt(fields[12]),
1038
+ weightedIOTime: this.safeParseInt(fields[13])
1039
+ });
1040
+ }
1041
+ }
1042
+ return stats;
1043
+ }
1044
+ parseMounts(content) {
1045
+ const lines = content.split('\n').filter(line => line.trim());
1046
+ const mounts = [];
1047
+ for (const line of lines) {
1048
+ const fields = line.trim().split(/\s+/);
1049
+ if (fields.length >= 6) {
1050
+ mounts.push({
1051
+ device: fields[0],
1052
+ mountPoint: fields[1],
1053
+ filesystem: fields[2],
1054
+ options: fields[3].split(','),
1055
+ dump: this.safeParseInt(fields[4]),
1056
+ pass: this.safeParseInt(fields[5])
1057
+ });
1058
+ }
1059
+ }
1060
+ return mounts;
1061
+ }
1062
+ parseFileSystems(output) {
1063
+ const lines = output.split('\n').filter(line => line.trim());
1064
+ const filesystems = [];
1065
+ for (const line of lines) {
1066
+ const trimmed = line.trim();
1067
+ if (trimmed) {
1068
+ const isNodev = trimmed.startsWith('nodev\t');
1069
+ const name = isNodev ? trimmed.substring(6) : trimmed;
1070
+ filesystems.push({
1071
+ name,
1072
+ supported: !isNodev
1073
+ });
1074
+ }
1075
+ }
1076
+ return filesystems;
1077
+ }
1078
+ parseNetworkConnections(output) {
1079
+ const lines = output.split('\n').slice(1); // 跳过标题行
1080
+ const connections = [];
1081
+ for (const line of lines) {
1082
+ const fields = line.trim().split(/\s+/);
1083
+ if (fields.length >= 5) {
1084
+ connections.push({
1085
+ protocol: fields[0],
1086
+ state: fields[1],
1087
+ localAddress: fields[4],
1088
+ foreignAddress: fields[5] || '*:*'
1089
+ });
1090
+ }
1091
+ }
1092
+ return connections;
1093
+ }
1094
+ parseNetstatConnections(output) {
1095
+ const lines = output.split('\n').filter(line => {
1096
+ const trimmed = line.trim();
1097
+ return trimmed && !trimmed.startsWith('Proto') && !trimmed.startsWith('Active');
1098
+ });
1099
+ const connections = [];
1100
+ for (const line of lines) {
1101
+ const fields = line.trim().split(/\s+/);
1102
+ if (fields.length < 5) {
1103
+ continue;
1104
+ }
1105
+ const protocol = fields[0].toLowerCase();
1106
+ const hasState = fields.length >= 6;
1107
+ const localFieldIndex = 3;
1108
+ const foreignFieldIndex = 4;
1109
+ connections.push({
1110
+ protocol,
1111
+ state: hasState ? fields[5].toLowerCase() : 'unknown',
1112
+ localAddress: fields[localFieldIndex],
1113
+ foreignAddress: fields[foreignFieldIndex] || '*:*'
1114
+ });
1115
+ }
1116
+ return connections;
1117
+ }
1118
+ parseDefaultGateway(output) {
1119
+ const lines = output.split('\n');
1120
+ for (const line of lines) {
1121
+ const trimmed = line.trim();
1122
+ if (!trimmed || !trimmed.startsWith('default')) {
1123
+ continue;
1124
+ }
1125
+ const fields = trimmed.split(/\s+/);
1126
+ if (fields.length === 0) {
1127
+ continue;
1128
+ }
1129
+ let gateway = null;
1130
+ let interfaceName = null;
1131
+ for (let i = 0; i < fields.length; i++) {
1132
+ const token = fields[i];
1133
+ if (token === 'via' && fields[i + 1]) {
1134
+ gateway = fields[i + 1];
1135
+ }
1136
+ else if (token === 'dev' && fields[i + 1]) {
1137
+ interfaceName = fields[i + 1];
1138
+ }
1139
+ }
1140
+ if (!gateway && fields.length > 1) {
1141
+ const candidate = fields[1];
1142
+ if (candidate && candidate !== 'dev' && candidate !== 'proto' && candidate !== 'metric' && candidate !== 'scope') {
1143
+ gateway = candidate;
1144
+ }
1145
+ }
1146
+ if (gateway !== null || interfaceName !== null) {
1147
+ return {
1148
+ gateway: gateway ?? null,
1149
+ interface: interfaceName ?? 'unknown'
1150
+ };
1151
+ }
1152
+ }
1153
+ return null;
1154
+ }
1155
+ parseOpenFiles(output) {
1156
+ const lines = output.split('\n');
1157
+ const files = [];
1158
+ for (const line of lines) {
1159
+ if (line.startsWith('n')) {
1160
+ files.push(line.substring(1));
1161
+ }
1162
+ }
1163
+ return files;
1164
+ }
1165
+ parseEnvironment(content) {
1166
+ const env = {};
1167
+ const variables = content.split('\0').filter(v => v);
1168
+ for (const variable of variables) {
1169
+ const equalIndex = variable.indexOf('=');
1170
+ if (equalIndex > 0) {
1171
+ const key = variable.substring(0, equalIndex);
1172
+ const value = variable.substring(equalIndex + 1);
1173
+ env[key] = value;
1174
+ }
1175
+ }
1176
+ return env;
1177
+ }
1178
+ parseSystemUsers(output) {
1179
+ const lines = output.split('\n').filter(line => line.trim());
1180
+ const users = [];
1181
+ for (const line of lines) {
1182
+ const fields = line.trim().split(/\s+/);
1183
+ if (fields.length >= 3) {
1184
+ users.push({
1185
+ user: fields[0],
1186
+ terminal: fields[1],
1187
+ loginTime: fields.slice(2).join(' ')
1188
+ });
1189
+ }
1190
+ }
1191
+ return users;
1192
+ }
1193
+ parseSystemServices(output) {
1194
+ const lines = output.split('\n').slice(1); // 跳过标题行
1195
+ const services = [];
1196
+ for (const line of lines) {
1197
+ const fields = line.trim().split(/\s+/);
1198
+ if (fields.length >= 4) {
1199
+ services.push({
1200
+ unit: fields[0],
1201
+ load: fields[1],
1202
+ active: fields[2],
1203
+ sub: fields[3],
1204
+ description: fields.slice(4).join(' ')
1205
+ });
1206
+ }
1207
+ }
1208
+ return services;
1209
+ }
1210
+ async delay(ms) {
1211
+ if (ms <= 0) {
1212
+ return;
1213
+ }
1214
+ await new Promise(resolve => setTimeout(resolve, ms));
1215
+ }
1216
+ /**
1217
+ * 推断主机架构
1218
+ *
1219
+ * 同时考虑 `uname -m`、`uname -a` 末尾字段与 `os.arch()`,过滤掉 `SMP` 等噪声标记,
1220
+ * 尽可能返回准确的 CPU 架构标识。
1221
+ */
1222
+ resolveArchitecture(unameFields, machineOutput) {
1223
+ const archPattern = /^(x86_64|amd64|arm64|aarch64|armv\d+l?|i[3-6]86|ppc64le|ppc64|s390x|mips64el|mips64|mipsel|loongarch\d*|riscv\d+|sparc64)$/i;
1224
+ const normalize = (value) => value?.trim() || '';
1225
+ const candidates = [];
1226
+ const normalizedMachine = normalize(machineOutput);
1227
+ if (normalizedMachine) {
1228
+ candidates.push(normalizedMachine);
1229
+ }
1230
+ for (let i = unameFields.length - 1; i >= 0; i--) {
1231
+ const token = normalize(unameFields[i]);
1232
+ if (token) {
1233
+ candidates.push(token);
1234
+ }
1235
+ }
1236
+ try {
1237
+ const runtimeArch = normalize(os_1.default.arch());
1238
+ if (runtimeArch) {
1239
+ candidates.push(runtimeArch);
1240
+ }
1241
+ }
1242
+ catch {
1243
+ // ignore runtime arch fetch errors
1244
+ }
1245
+ for (const candidate of candidates) {
1246
+ if (candidate && archPattern.test(candidate)) {
1247
+ return candidate;
1248
+ }
1249
+ }
1250
+ return 'Unknown';
1251
+ }
1252
+ /**
1253
+ * 归纳命令执行阶段的错误信息
1254
+ *
1255
+ * 便于在调用栈中保留主、次命令的失败原因,帮助上层监控器输出更具可读性的诊断数据。
1256
+ */
1257
+ summarizeErrorDetails(error) {
1258
+ if (!error) {
1259
+ return { message: 'Unknown error' };
1260
+ }
1261
+ if (error instanceof errors_1.MonitorError) {
1262
+ return {
1263
+ code: error.code,
1264
+ message: error.message,
1265
+ details: error.details || null
1266
+ };
1267
+ }
1268
+ if (error instanceof Error) {
1269
+ return {
1270
+ name: error.name,
1271
+ message: error.message
1272
+ };
1273
+ }
1274
+ return { message: String(error) };
1275
+ }
1276
+ /**
1277
+ * 检测当前进程是否运行在容器环境中
1278
+ *
1279
+ * 通过常见标记文件和 cgroup 信息判断,若命中则代表部分系统能力(如 systemd)不可用。
1280
+ */
1281
+ detectContainerEnvironment() {
1282
+ try {
1283
+ const indicatorPaths = ['/.dockerenv', '/run/.containerenv'];
1284
+ for (const path of indicatorPaths) {
1285
+ if (fsSync.existsSync(path)) {
1286
+ return true;
1287
+ }
1288
+ }
1289
+ const cgroupPath = '/proc/1/cgroup';
1290
+ if (fsSync.existsSync(cgroupPath)) {
1291
+ const content = fsSync.readFileSync(cgroupPath, 'utf8');
1292
+ if (/(docker|containerd|kubepods|lxc|podman)/i.test(content)) {
1293
+ return true;
1294
+ }
1295
+ }
1296
+ const envIndicators = ['CONTAINER', 'KUBERNETES_SERVICE_HOST'];
1297
+ if (envIndicators.some(key => process.env[key])) {
1298
+ return true;
1299
+ }
1300
+ }
1301
+ catch {
1302
+ // 检测失败时默认视为非容器环境
1303
+ }
1304
+ return false;
1305
+ }
1306
+ }
1307
+ exports.LinuxAdapter = LinuxAdapter;
1308
+ //# sourceMappingURL=linux-adapter.js.map