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