xypriss 1.2.3 → 1.3.0

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 (103) hide show
  1. package/README.md +138 -3
  2. package/dist/cjs/mods/security/src/components/cache/index.js +1 -1
  3. package/dist/cjs/shared/logger/Logger.js +1 -0
  4. package/dist/cjs/shared/logger/Logger.js.map +1 -1
  5. package/dist/cjs/src/cluster/bun-cluster-manager.js +1567 -0
  6. package/dist/cjs/src/cluster/bun-cluster-manager.js.map +1 -0
  7. package/dist/cjs/src/cluster/cluster-manager.js +1 -1
  8. package/dist/cjs/src/cluster/cluster-manager.js.map +1 -1
  9. package/dist/cjs/src/cluster/index.js +25 -6
  10. package/dist/cjs/src/cluster/index.js.map +1 -1
  11. package/dist/cjs/src/cluster/memory-manager.js +463 -0
  12. package/dist/cjs/src/cluster/memory-manager.js.map +1 -0
  13. package/dist/cjs/src/cluster/modules/BunIPCManager.js +603 -0
  14. package/dist/cjs/src/cluster/modules/BunIPCManager.js.map +1 -0
  15. package/dist/cjs/src/cluster/modules/ClusterFactory.js +22 -1
  16. package/dist/cjs/src/cluster/modules/ClusterFactory.js.map +1 -1
  17. package/dist/cjs/src/cluster/modules/CpuMonitor.js +658 -0
  18. package/dist/cjs/src/cluster/modules/CpuMonitor.js.map +1 -0
  19. package/dist/cjs/src/cluster/modules/ProcessMonitor.js +513 -0
  20. package/dist/cjs/src/cluster/modules/ProcessMonitor.js.map +1 -0
  21. package/dist/cjs/src/plugins/server-maintenance-plugin.js +1 -1
  22. package/dist/cjs/src/server/FastServer.js +64 -43
  23. package/dist/cjs/src/server/FastServer.js.map +1 -1
  24. package/dist/cjs/src/server/components/fastapi/ClusterManagerComponent.js +226 -10
  25. package/dist/cjs/src/server/components/fastapi/ClusterManagerComponent.js.map +1 -1
  26. package/dist/cjs/src/server/const/Cluster.config.js +174 -31
  27. package/dist/cjs/src/server/const/Cluster.config.js.map +1 -1
  28. package/dist/cjs/src/server/const/default.js +11 -2
  29. package/dist/cjs/src/server/const/default.js.map +1 -1
  30. package/dist/cjs/src/server/utils/PortManager.js +26 -15
  31. package/dist/cjs/src/server/utils/PortManager.js.map +1 -1
  32. package/dist/esm/mods/security/src/components/cache/index.js +1 -1
  33. package/dist/esm/shared/logger/Logger.js +1 -0
  34. package/dist/esm/shared/logger/Logger.js.map +1 -1
  35. package/dist/esm/src/cluster/bun-cluster-manager.js +1565 -0
  36. package/dist/esm/src/cluster/bun-cluster-manager.js.map +1 -0
  37. package/dist/esm/src/cluster/cluster-manager.js +1 -1
  38. package/dist/esm/src/cluster/cluster-manager.js.map +1 -1
  39. package/dist/esm/src/cluster/index.js +25 -6
  40. package/dist/esm/src/cluster/index.js.map +1 -1
  41. package/dist/esm/src/cluster/memory-manager.js +461 -0
  42. package/dist/esm/src/cluster/memory-manager.js.map +1 -0
  43. package/dist/esm/src/cluster/modules/BunIPCManager.js +601 -0
  44. package/dist/esm/src/cluster/modules/BunIPCManager.js.map +1 -0
  45. package/dist/esm/src/cluster/modules/ClusterFactory.js +22 -1
  46. package/dist/esm/src/cluster/modules/ClusterFactory.js.map +1 -1
  47. package/dist/esm/src/cluster/modules/CpuMonitor.js +656 -0
  48. package/dist/esm/src/cluster/modules/CpuMonitor.js.map +1 -0
  49. package/dist/esm/src/cluster/modules/ProcessMonitor.js +511 -0
  50. package/dist/esm/src/cluster/modules/ProcessMonitor.js.map +1 -0
  51. package/dist/esm/src/plugins/server-maintenance-plugin.js +1 -1
  52. package/dist/esm/src/server/FastServer.js +64 -43
  53. package/dist/esm/src/server/FastServer.js.map +1 -1
  54. package/dist/esm/src/server/components/fastapi/ClusterManagerComponent.js +226 -10
  55. package/dist/esm/src/server/components/fastapi/ClusterManagerComponent.js.map +1 -1
  56. package/dist/esm/src/server/const/Cluster.config.js +174 -31
  57. package/dist/esm/src/server/const/Cluster.config.js.map +1 -1
  58. package/dist/esm/src/server/const/default.js +11 -2
  59. package/dist/esm/src/server/const/default.js.map +1 -1
  60. package/dist/esm/src/server/utils/PortManager.js +26 -15
  61. package/dist/esm/src/server/utils/PortManager.js.map +1 -1
  62. package/dist/index.d.ts +78 -1
  63. package/package.json +3 -1
  64. package/dist/cjs/src/plugins/modules/network/index.js +0 -120
  65. package/dist/cjs/src/plugins/modules/network/index.js.map +0 -1
  66. package/dist/cjs/src/server/plugins/PluginEngine.js +0 -378
  67. package/dist/cjs/src/server/plugins/PluginEngine.js.map +0 -1
  68. package/dist/cjs/src/server/plugins/PluginRegistry.js +0 -339
  69. package/dist/cjs/src/server/plugins/PluginRegistry.js.map +0 -1
  70. package/dist/cjs/src/server/plugins/builtin/JWTAuthPlugin.js +0 -591
  71. package/dist/cjs/src/server/plugins/builtin/JWTAuthPlugin.js.map +0 -1
  72. package/dist/cjs/src/server/plugins/builtin/ResponseTimePlugin.js +0 -413
  73. package/dist/cjs/src/server/plugins/builtin/ResponseTimePlugin.js.map +0 -1
  74. package/dist/cjs/src/server/plugins/builtin/SmartCachePlugin.js +0 -843
  75. package/dist/cjs/src/server/plugins/builtin/SmartCachePlugin.js.map +0 -1
  76. package/dist/cjs/src/server/plugins/core/CachePlugin.js +0 -1975
  77. package/dist/cjs/src/server/plugins/core/CachePlugin.js.map +0 -1
  78. package/dist/cjs/src/server/plugins/core/PerformancePlugin.js +0 -894
  79. package/dist/cjs/src/server/plugins/core/PerformancePlugin.js.map +0 -1
  80. package/dist/cjs/src/server/plugins/core/SecurityPlugin.js +0 -799
  81. package/dist/cjs/src/server/plugins/core/SecurityPlugin.js.map +0 -1
  82. package/dist/cjs/src/server/plugins/types/PluginTypes.js +0 -47
  83. package/dist/cjs/src/server/plugins/types/PluginTypes.js.map +0 -1
  84. package/dist/esm/src/plugins/modules/network/index.js +0 -109
  85. package/dist/esm/src/plugins/modules/network/index.js.map +0 -1
  86. package/dist/esm/src/server/plugins/PluginEngine.js +0 -376
  87. package/dist/esm/src/server/plugins/PluginEngine.js.map +0 -1
  88. package/dist/esm/src/server/plugins/PluginRegistry.js +0 -337
  89. package/dist/esm/src/server/plugins/PluginRegistry.js.map +0 -1
  90. package/dist/esm/src/server/plugins/builtin/JWTAuthPlugin.js +0 -589
  91. package/dist/esm/src/server/plugins/builtin/JWTAuthPlugin.js.map +0 -1
  92. package/dist/esm/src/server/plugins/builtin/ResponseTimePlugin.js +0 -411
  93. package/dist/esm/src/server/plugins/builtin/ResponseTimePlugin.js.map +0 -1
  94. package/dist/esm/src/server/plugins/builtin/SmartCachePlugin.js +0 -841
  95. package/dist/esm/src/server/plugins/builtin/SmartCachePlugin.js.map +0 -1
  96. package/dist/esm/src/server/plugins/core/CachePlugin.js +0 -1973
  97. package/dist/esm/src/server/plugins/core/CachePlugin.js.map +0 -1
  98. package/dist/esm/src/server/plugins/core/PerformancePlugin.js +0 -872
  99. package/dist/esm/src/server/plugins/core/PerformancePlugin.js.map +0 -1
  100. package/dist/esm/src/server/plugins/core/SecurityPlugin.js +0 -797
  101. package/dist/esm/src/server/plugins/core/SecurityPlugin.js.map +0 -1
  102. package/dist/esm/src/server/plugins/types/PluginTypes.js +0 -47
  103. package/dist/esm/src/server/plugins/types/PluginTypes.js.map +0 -1
@@ -0,0 +1,656 @@
1
+ import { logger } from '../../../shared/logger/Logger.js';
2
+
3
+ /**
4
+ * CPU Monitoring Module for XyPriss Cluster Management
5
+ * Provides sophisticated CPU usage tracking and monitoring capabilities
6
+ * Supports multiple platforms with fallback mechanisms
7
+ */
8
+ /**
9
+ * Enhanced CPU Monitor with sophisticated tracking capabilities
10
+ */
11
+ class CpuMonitor {
12
+ constructor(config = {}) {
13
+ this.history = [];
14
+ this.processHistory = new Map();
15
+ this.isMonitoring = false;
16
+ this.config = {
17
+ enabled: true,
18
+ sampleInterval: 5000, // 5 seconds
19
+ historySize: 100, // Keep 100 samples (~8 minutes at 5s intervals)
20
+ smoothingFactor: 0.3,
21
+ alertThresholds: {
22
+ warning: 70,
23
+ critical: 90,
24
+ },
25
+ ...config,
26
+ };
27
+ }
28
+ /**
29
+ * Start CPU monitoring
30
+ */
31
+ startMonitoring() {
32
+ if (this.isMonitoring || !this.config.enabled) {
33
+ return;
34
+ }
35
+ this.isMonitoring = true;
36
+ logger.info("cluster", "Starting CPU monitoring");
37
+ this.monitoringInterval = setInterval(async () => {
38
+ try {
39
+ await this.collectSystemStats();
40
+ }
41
+ catch (error) {
42
+ logger.error("cluster", "Error collecting CPU stats:", error);
43
+ }
44
+ }, this.config.sampleInterval);
45
+ }
46
+ /**
47
+ * Stop CPU monitoring
48
+ */
49
+ stopMonitoring() {
50
+ if (!this.isMonitoring) {
51
+ return;
52
+ }
53
+ this.isMonitoring = false;
54
+ if (this.monitoringInterval) {
55
+ clearInterval(this.monitoringInterval);
56
+ this.monitoringInterval = undefined;
57
+ }
58
+ logger.info("cluster", "Stopped CPU monitoring");
59
+ }
60
+ /**
61
+ * Calculate sophisticated CPU usage for the cluster
62
+ */
63
+ async calculateClusterCpuUsage(workers) {
64
+ try {
65
+ const activeWorkers = workers.filter((w) => w.health.status === "healthy");
66
+ if (activeWorkers.length === 0) {
67
+ return 0;
68
+ }
69
+ // Get system-wide CPU usage
70
+ const systemStats = await this.getSystemCpuStats();
71
+ // Calculate worker-specific CPU usage
72
+ const workerCpuPromises = activeWorkers.map(async (worker) => {
73
+ if (worker.subprocess && !worker.subprocess.killed) {
74
+ return await this.getProcessCpuUsage(worker.subprocess.pid);
75
+ }
76
+ return 0;
77
+ });
78
+ const workerCpuUsages = await Promise.all(workerCpuPromises);
79
+ const totalWorkerCpu = workerCpuUsages.reduce((sum, usage) => sum + usage, 0);
80
+ // Combine system and worker metrics with intelligent weighting
81
+ const systemWeight = 0.4;
82
+ const workerWeight = 0.6;
83
+ const weightedCpu = systemStats.overall * systemWeight +
84
+ Math.min(totalWorkerCpu, 100) * workerWeight;
85
+ // Apply smoothing if we have historical data
86
+ const smoothedCpu = this.applySmoothingToUsage(weightedCpu);
87
+ return Math.min(Math.round(smoothedCpu), 100);
88
+ }
89
+ catch (error) {
90
+ logger.error("cluster", "Error calculating cluster CPU usage:", error);
91
+ return 0;
92
+ }
93
+ }
94
+ /**
95
+ * Get CPU usage for a specific process with enhanced accuracy
96
+ */
97
+ async getProcessCpuUsage(pid) {
98
+ try {
99
+ const stats = await this.getProcessCpuStats(pid);
100
+ // Store in history for trend analysis
101
+ this.updateProcessHistory(pid, stats);
102
+ return stats.usage;
103
+ }
104
+ catch (error) {
105
+ logger.debug("cluster", `Error getting CPU usage for PID ${pid}:`, error);
106
+ return 0;
107
+ }
108
+ }
109
+ /**
110
+ * Get detailed CPU statistics for a process
111
+ */
112
+ async getProcessCpuStats(pid) {
113
+ const timestamp = Date.now();
114
+ try {
115
+ if (process.platform === "linux") {
116
+ return await this.getLinuxProcessCpuStats(pid, timestamp);
117
+ }
118
+ else if (process.platform === "darwin") {
119
+ return await this.getMacOSProcessCpuStats(pid, timestamp);
120
+ }
121
+ else if (process.platform === "win32") {
122
+ return await this.getWindowsProcessCpuStats(pid, timestamp);
123
+ }
124
+ else {
125
+ // Fallback for unsupported platforms
126
+ return {
127
+ pid,
128
+ usage: 0,
129
+ userTime: 0,
130
+ systemTime: 0,
131
+ totalTime: 0,
132
+ timestamp,
133
+ };
134
+ }
135
+ }
136
+ catch (error) {
137
+ throw new Error(`Failed to get process CPU stats for PID ${pid}: ${error}`);
138
+ }
139
+ }
140
+ /**
141
+ * Get system-wide CPU statistics
142
+ */
143
+ async getSystemCpuStats() {
144
+ const timestamp = Date.now();
145
+ const loadAverage = process.platform !== "win32" ? require("os").loadavg() : [0, 0, 0];
146
+ try {
147
+ if (process.platform === "linux") {
148
+ return await this.getLinuxSystemCpuStats(timestamp, loadAverage);
149
+ }
150
+ else if (process.platform === "darwin") {
151
+ return await this.getMacOSSystemCpuStats(timestamp, loadAverage);
152
+ }
153
+ else if (process.platform === "win32") {
154
+ return await this.getWindowsSystemCpuStats(timestamp);
155
+ }
156
+ else {
157
+ // Fallback
158
+ return {
159
+ overall: 0,
160
+ cores: [],
161
+ loadAverage,
162
+ processes: 0,
163
+ timestamp,
164
+ };
165
+ }
166
+ }
167
+ catch (error) {
168
+ logger.error("cluster", "Error getting system CPU stats:", error);
169
+ return {
170
+ overall: 0,
171
+ cores: [],
172
+ loadAverage,
173
+ processes: 0,
174
+ timestamp,
175
+ };
176
+ }
177
+ }
178
+ /**
179
+ * Apply exponential smoothing to CPU usage
180
+ */
181
+ applySmoothingToUsage(currentUsage) {
182
+ if (this.history.length === 0) {
183
+ return currentUsage;
184
+ }
185
+ const lastUsage = this.history[this.history.length - 1].usage;
186
+ const smoothingFactor = this.config.smoothingFactor;
187
+ return (smoothingFactor * currentUsage + (1 - smoothingFactor) * lastUsage);
188
+ }
189
+ /**
190
+ * Update process history for trend analysis
191
+ */
192
+ updateProcessHistory(pid, stats) {
193
+ if (!this.processHistory.has(pid)) {
194
+ this.processHistory.set(pid, []);
195
+ }
196
+ const history = this.processHistory.get(pid);
197
+ history.push(stats);
198
+ // Keep only recent history
199
+ if (history.length > this.config.historySize) {
200
+ history.shift();
201
+ }
202
+ }
203
+ /**
204
+ * Collect and store system-wide statistics
205
+ */
206
+ async collectSystemStats() {
207
+ try {
208
+ const systemStats = await this.getSystemCpuStats();
209
+ const dataPoint = {
210
+ timestamp: systemStats.timestamp,
211
+ usage: systemStats.overall,
212
+ processes: new Map(),
213
+ };
214
+ this.history.push(dataPoint);
215
+ // Keep only recent history
216
+ if (this.history.length > this.config.historySize) {
217
+ this.history.shift();
218
+ }
219
+ // Store system stats for future reference if needed
220
+ // Check for alerts
221
+ this.checkAlertThresholds(systemStats.overall);
222
+ }
223
+ catch (error) {
224
+ logger.error("cluster", "Error collecting system stats:", error);
225
+ }
226
+ }
227
+ /**
228
+ * Check if CPU usage exceeds alert thresholds
229
+ */
230
+ checkAlertThresholds(usage) {
231
+ if (usage >= this.config.alertThresholds.critical) {
232
+ logger.warn("cluster", `Critical CPU usage detected: ${usage.toFixed(1)}%`);
233
+ }
234
+ else if (usage >= this.config.alertThresholds.warning) {
235
+ logger.warn("cluster", `High CPU usage detected: ${usage.toFixed(1)}%`);
236
+ }
237
+ }
238
+ /**
239
+ * Get Linux process CPU statistics using /proc filesystem
240
+ */
241
+ async getLinuxProcessCpuStats(pid, timestamp) {
242
+ const fs = await import('fs');
243
+ try {
244
+ // Read process stat file
245
+ const statData = await fs.promises.readFile(`/proc/${pid}/stat`, "utf8");
246
+ const statFields = statData.trim().split(/\s+/);
247
+ if (statFields.length < 15) {
248
+ throw new Error("Invalid stat file format");
249
+ }
250
+ const utime = parseInt(statFields[13]); // User time in clock ticks
251
+ const stime = parseInt(statFields[14]); // System time in clock ticks
252
+ const totalTime = utime + stime;
253
+ // Get system clock ticks per second
254
+ const clockTicks = 100; // Usually 100 on Linux, but could vary
255
+ // Convert to milliseconds
256
+ const userTimeMs = (utime / clockTicks) * 1000;
257
+ const systemTimeMs = (stime / clockTicks) * 1000;
258
+ const totalTimeMs = (totalTime / clockTicks) * 1000;
259
+ // Calculate CPU usage percentage
260
+ let usage = 0;
261
+ const previousStats = this.getLastProcessStats(pid);
262
+ if (previousStats) {
263
+ const timeDelta = timestamp - previousStats.timestamp;
264
+ const cpuTimeDelta = totalTimeMs - previousStats.totalTime;
265
+ if (timeDelta > 0) {
266
+ usage = Math.min(100, (cpuTimeDelta / timeDelta) * 100);
267
+ }
268
+ }
269
+ return {
270
+ pid,
271
+ usage,
272
+ userTime: userTimeMs,
273
+ systemTime: systemTimeMs,
274
+ totalTime: totalTimeMs,
275
+ timestamp,
276
+ };
277
+ }
278
+ catch (error) {
279
+ throw new Error(`Failed to read Linux process stats: ${error}`);
280
+ }
281
+ }
282
+ /**
283
+ * Get macOS process CPU statistics using ps command
284
+ */
285
+ async getMacOSProcessCpuStats(pid, timestamp) {
286
+ const { spawn } = await import('child_process');
287
+ return new Promise((resolve, reject) => {
288
+ const ps = spawn("ps", ["-o", "pcpu=,time=", "-p", pid.toString()]);
289
+ let output = "";
290
+ ps.stdout.on("data", (data) => {
291
+ output += data.toString();
292
+ });
293
+ ps.on("close", (code) => {
294
+ if (code === 0) {
295
+ try {
296
+ const lines = output.trim().split("\n");
297
+ const data = lines[lines.length - 1]
298
+ .trim()
299
+ .split(/\s+/);
300
+ const cpuPercent = parseFloat(data[0]) || 0;
301
+ const timeStr = data[1] || "0:00.00";
302
+ // Parse time format (MM:SS.ss or HH:MM:SS.ss)
303
+ const timeParts = timeStr.split(":");
304
+ let totalSeconds = 0;
305
+ if (timeParts.length === 2) {
306
+ totalSeconds =
307
+ parseInt(timeParts[0]) * 60 +
308
+ parseFloat(timeParts[1]);
309
+ }
310
+ else if (timeParts.length === 3) {
311
+ totalSeconds =
312
+ parseInt(timeParts[0]) * 3600 +
313
+ parseInt(timeParts[1]) * 60 +
314
+ parseFloat(timeParts[2]);
315
+ }
316
+ const totalTimeMs = totalSeconds * 1000;
317
+ resolve({
318
+ pid,
319
+ usage: cpuPercent,
320
+ userTime: totalTimeMs * 0.7, // Approximate split
321
+ systemTime: totalTimeMs * 0.3,
322
+ totalTime: totalTimeMs,
323
+ timestamp,
324
+ });
325
+ }
326
+ catch (error) {
327
+ reject(new Error(`Failed to parse macOS ps output: ${error}`));
328
+ }
329
+ }
330
+ else {
331
+ reject(new Error(`ps command failed with code ${code}`));
332
+ }
333
+ });
334
+ ps.on("error", reject);
335
+ });
336
+ }
337
+ /**
338
+ * Get Windows process CPU statistics using wmic
339
+ */
340
+ async getWindowsProcessCpuStats(pid, timestamp) {
341
+ const { spawn } = await import('child_process');
342
+ return new Promise((resolve, reject) => {
343
+ const wmic = spawn("wmic", [
344
+ "process",
345
+ "where",
346
+ `ProcessId=${pid}`,
347
+ "get",
348
+ "PageFileUsage,UserModeTime,KernelModeTime",
349
+ "/format:csv",
350
+ ]);
351
+ let output = "";
352
+ wmic.stdout.on("data", (data) => {
353
+ output += data.toString();
354
+ });
355
+ wmic.on("close", (code) => {
356
+ if (code === 0) {
357
+ try {
358
+ const lines = output.trim().split("\n");
359
+ const dataLine = lines.find((line) => line.includes(pid.toString()));
360
+ if (!dataLine) {
361
+ throw new Error("Process not found in wmic output");
362
+ }
363
+ const fields = dataLine.split(",");
364
+ const kernelTime = parseInt(fields[1]) || 0;
365
+ const userTime = parseInt(fields[2]) || 0;
366
+ // Convert from 100-nanosecond intervals to milliseconds
367
+ const kernelTimeMs = kernelTime / 10000;
368
+ const userTimeMs = userTime / 10000;
369
+ const totalTimeMs = kernelTimeMs + userTimeMs;
370
+ // Calculate usage based on previous measurement
371
+ let usage = 0;
372
+ const previousStats = this.getLastProcessStats(pid);
373
+ if (previousStats) {
374
+ const timeDelta = timestamp - previousStats.timestamp;
375
+ const cpuTimeDelta = totalTimeMs - previousStats.totalTime;
376
+ if (timeDelta > 0) {
377
+ usage = Math.min(100, (cpuTimeDelta / timeDelta) * 100);
378
+ }
379
+ }
380
+ resolve({
381
+ pid,
382
+ usage,
383
+ userTime: userTimeMs,
384
+ systemTime: kernelTimeMs,
385
+ totalTime: totalTimeMs,
386
+ timestamp,
387
+ });
388
+ }
389
+ catch (error) {
390
+ reject(new Error(`Failed to parse Windows wmic output: ${error}`));
391
+ }
392
+ }
393
+ else {
394
+ reject(new Error(`wmic command failed with code ${code}`));
395
+ }
396
+ });
397
+ wmic.on("error", reject);
398
+ });
399
+ }
400
+ /**
401
+ * Get the last recorded stats for a process
402
+ */
403
+ getLastProcessStats(pid) {
404
+ const history = this.processHistory.get(pid);
405
+ return history && history.length > 0
406
+ ? history[history.length - 1]
407
+ : null;
408
+ }
409
+ /**
410
+ * Get Linux system CPU statistics using /proc/stat
411
+ */
412
+ async getLinuxSystemCpuStats(timestamp, loadAverage) {
413
+ const fs = await import('fs');
414
+ try {
415
+ const statData = await fs.promises.readFile("/proc/stat", "utf8");
416
+ const lines = statData.split("\n");
417
+ // Parse overall CPU line
418
+ const cpuLine = lines[0];
419
+ const cpuTimes = cpuLine.split(/\s+/).slice(1).map(Number);
420
+ const idle = cpuTimes[3] || 0;
421
+ const iowait = cpuTimes[4] || 0;
422
+ const total = cpuTimes.reduce((sum, time) => sum + time, 0);
423
+ const overall = total > 0
424
+ ? Math.max(0, 100 - ((idle + iowait) / total) * 100)
425
+ : 0;
426
+ // Parse per-core CPU usage
427
+ const cores = [];
428
+ for (let i = 1; i < lines.length; i++) {
429
+ const line = lines[i];
430
+ if (line.startsWith("cpu")) {
431
+ const coreTimes = line.split(/\s+/).slice(1).map(Number);
432
+ if (coreTimes.length >= 4) {
433
+ const coreIdle = coreTimes[3] || 0;
434
+ const coreIowait = coreTimes[4] || 0;
435
+ const coreTotal = coreTimes.reduce((sum, time) => sum + time, 0);
436
+ const coreUsage = coreTotal > 0
437
+ ? Math.max(0, 100 -
438
+ ((coreIdle + coreIowait) /
439
+ coreTotal) *
440
+ 100)
441
+ : 0;
442
+ cores.push(coreUsage);
443
+ }
444
+ }
445
+ else {
446
+ break;
447
+ }
448
+ }
449
+ // Get process count
450
+ let processes = 0;
451
+ try {
452
+ const procDirs = await fs.promises.readdir("/proc");
453
+ processes = procDirs.filter((dir) => /^\d+$/.test(dir)).length;
454
+ }
455
+ catch {
456
+ processes = 0;
457
+ }
458
+ return {
459
+ overall,
460
+ cores,
461
+ loadAverage,
462
+ processes,
463
+ timestamp,
464
+ };
465
+ }
466
+ catch (error) {
467
+ throw new Error(`Failed to read Linux system stats: ${error}`);
468
+ }
469
+ }
470
+ /**
471
+ * Get macOS system CPU statistics using system commands
472
+ */
473
+ async getMacOSSystemCpuStats(timestamp, loadAverage) {
474
+ const { spawn } = await import('child_process');
475
+ return new Promise((resolve, reject) => {
476
+ // Use iostat to get CPU usage
477
+ const iostat = spawn("iostat", ["-c", "1", "1"]);
478
+ let output = "";
479
+ iostat.stdout.on("data", (data) => {
480
+ output += data.toString();
481
+ });
482
+ iostat.on("close", async (code) => {
483
+ if (code === 0) {
484
+ try {
485
+ const lines = output.trim().split("\n");
486
+ const cpuLine = lines[lines.length - 1];
487
+ const values = cpuLine.trim().split(/\s+/);
488
+ // iostat format: %user %nice %sys %idle
489
+ const idle = parseFloat(values[3]) || 0;
490
+ // Calculate overall CPU usage (100 - idle)
491
+ const overall = Math.max(0, 100 - idle);
492
+ // Get process count
493
+ let processes = 0;
494
+ try {
495
+ const ps = spawn("ps", ["-A"]);
496
+ let psOutput = "";
497
+ ps.stdout.on("data", (data) => {
498
+ psOutput += data.toString();
499
+ });
500
+ ps.on("close", () => {
501
+ processes = psOutput.split("\n").length - 2; // Subtract header and empty line
502
+ resolve({
503
+ overall,
504
+ cores: [], // macOS per-core stats require more complex parsing
505
+ loadAverage,
506
+ processes,
507
+ timestamp,
508
+ });
509
+ });
510
+ }
511
+ catch {
512
+ resolve({
513
+ overall,
514
+ cores: [],
515
+ loadAverage,
516
+ processes: 0,
517
+ timestamp,
518
+ });
519
+ }
520
+ }
521
+ catch (error) {
522
+ reject(new Error(`Failed to parse macOS iostat output: ${error}`));
523
+ }
524
+ }
525
+ else {
526
+ reject(new Error(`iostat command failed with code ${code}`));
527
+ }
528
+ });
529
+ iostat.on("error", reject);
530
+ });
531
+ }
532
+ /**
533
+ * Get Windows system CPU statistics using wmic
534
+ */
535
+ async getWindowsSystemCpuStats(timestamp) {
536
+ const { spawn } = await import('child_process');
537
+ return new Promise((resolve, reject) => {
538
+ const wmic = spawn("wmic", [
539
+ "cpu",
540
+ "get",
541
+ "loadpercentage",
542
+ "/value",
543
+ ]);
544
+ let output = "";
545
+ wmic.stdout.on("data", (data) => {
546
+ output += data.toString();
547
+ });
548
+ wmic.on("close", async (code) => {
549
+ if (code === 0) {
550
+ try {
551
+ const lines = output.split("\n");
552
+ const loadLine = lines.find((line) => line.includes("LoadPercentage"));
553
+ let overall = 0;
554
+ if (loadLine) {
555
+ const match = loadLine.match(/LoadPercentage=(\d+)/);
556
+ if (match) {
557
+ overall = parseInt(match[1]);
558
+ }
559
+ }
560
+ // Get process count
561
+ let processes = 0;
562
+ try {
563
+ const tasklist = spawn("tasklist", ["/fo", "csv"]);
564
+ let taskOutput = "";
565
+ tasklist.stdout.on("data", (data) => {
566
+ taskOutput += data.toString();
567
+ });
568
+ tasklist.on("close", () => {
569
+ processes = taskOutput.split("\n").length - 2; // Subtract header and empty line
570
+ resolve({
571
+ overall,
572
+ cores: [], // Windows per-core stats require additional commands
573
+ loadAverage: [0, 0, 0], // Windows doesn't have load average
574
+ processes,
575
+ timestamp,
576
+ });
577
+ });
578
+ }
579
+ catch {
580
+ resolve({
581
+ overall,
582
+ cores: [],
583
+ loadAverage: [0, 0, 0],
584
+ processes: 0,
585
+ timestamp,
586
+ });
587
+ }
588
+ }
589
+ catch (error) {
590
+ reject(new Error(`Failed to parse Windows wmic output: ${error}`));
591
+ }
592
+ }
593
+ else {
594
+ reject(new Error(`wmic command failed with code ${code}`));
595
+ }
596
+ });
597
+ wmic.on("error", reject);
598
+ });
599
+ }
600
+ /**
601
+ * Get CPU usage trend for a process
602
+ */
603
+ getProcessCpuTrend(pid, samples = 10) {
604
+ const history = this.processHistory.get(pid);
605
+ if (!history || history.length === 0) {
606
+ return [];
607
+ }
608
+ const recentHistory = history.slice(-samples);
609
+ return recentHistory.map((stats) => stats.usage);
610
+ }
611
+ /**
612
+ * Get system CPU usage trend
613
+ */
614
+ getSystemCpuTrend(samples = 10) {
615
+ if (this.history.length === 0) {
616
+ return [];
617
+ }
618
+ const recentHistory = this.history.slice(-samples);
619
+ return recentHistory.map((point) => point.usage);
620
+ }
621
+ /**
622
+ * Get current configuration
623
+ */
624
+ getConfig() {
625
+ return { ...this.config };
626
+ }
627
+ /**
628
+ * Update configuration
629
+ */
630
+ updateConfig(newConfig) {
631
+ this.config = { ...this.config, ...newConfig };
632
+ // Restart monitoring if interval changed
633
+ if (this.isMonitoring && newConfig.sampleInterval) {
634
+ this.stopMonitoring();
635
+ this.startMonitoring();
636
+ }
637
+ }
638
+ /**
639
+ * Clear all historical data
640
+ */
641
+ clearHistory() {
642
+ this.history = [];
643
+ this.processHistory.clear();
644
+ // Clear any cached system stats if needed
645
+ logger.info("cluster", "CPU monitoring history cleared");
646
+ }
647
+ /**
648
+ * Get monitoring status
649
+ */
650
+ isActive() {
651
+ return this.isMonitoring;
652
+ }
653
+ }
654
+
655
+ export { CpuMonitor };
656
+ //# sourceMappingURL=CpuMonitor.js.map