UNPKG

polyv-live-cli

Version:

CLI tool for managing PolyV live streaming services.

642 lines 24.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.SystemResourcePanel = void 0; const blessed = __importStar(require("blessed")); const contrib = __importStar(require("blessed-contrib")); const base_component_1 = require("./base.component"); const system_resource_service_1 = require("../services/system-resource.service"); let screen = null; const getScreen = () => { if (!screen) { try { screen = blessed.screen({ smartCSR: true, dockBorders: true, }); } catch (error) { screen = { render: () => { }, destroy: () => { }, }; } } return screen; }; class SystemResourcePanel extends base_component_1.BaseComponent { constructor(config, eventBus) { super(config, eventBus); this.currentResources = null; this.networkHistory = []; this.cpuHistory = []; this.memoryHistory = []; this.maxNetworkHistorySize = 60; this.maxCpuHistorySize = 60; this.maxMemoryHistorySize = 60; this.alertThresholds = { cpu: { warning: 70, critical: 85 }, memory: { warning: 75, critical: 90 }, network: { warning: 10, critical: 50 }, }; this.isGracefullyDegraded = false; this.lastNetworkBytes = { in: 0, out: 0, timestamp: 0 }; this.systemResourceService = new system_resource_service_1.SystemResourceService(); this.setupResourceService(); this.loadAlertThresholds(); } loadAlertThresholds() { const alertConfig = this.config.config['alertThresholds']; if (alertConfig) { this.alertThresholds = { cpu: { warning: alertConfig.cpu?.warning || this.alertThresholds.cpu.warning, critical: alertConfig.cpu?.critical || this.alertThresholds.cpu.critical, }, memory: { warning: alertConfig.memory?.warning || this.alertThresholds.memory.warning, critical: alertConfig.memory?.critical || this.alertThresholds.memory.critical, }, network: { warning: alertConfig.network?.warning || this.alertThresholds.network.warning, critical: alertConfig.network?.critical || this.alertThresholds.network.critical, }, }; } } updateAlertThresholds(newThresholds) { if (newThresholds.cpu) { this.alertThresholds.cpu = { ...this.alertThresholds.cpu, ...newThresholds.cpu }; } if (newThresholds.memory) { this.alertThresholds.memory = { ...this.alertThresholds.memory, ...newThresholds.memory }; } if (newThresholds.network) { this.alertThresholds.network = { ...this.alertThresholds.network, ...newThresholds.network }; } } getAlertThresholds() { return { ...this.alertThresholds }; } setupResourceService() { this.systemResourceService.on('resourceUpdate', (resources) => { this.currentResources = resources; this.updateNetworkHistory(resources); this.updateCpuHistory(resources); this.updateMemoryHistory(resources); this.update(resources); }); this.systemResourceService.on('error', (error) => { this.handleResourceError(error); }); } createWidget() { try { this.widget = blessed.box({ parent: getScreen(), top: this.config.position.y || 0, left: this.config.position.x || 0, width: this.config.position.width || '100%', height: this.config.position.height || '100%', label: ' System Resources ', border: { type: 'line' }, style: { border: { fg: 'blue' }, label: { fg: 'white', bold: true }, }, }); this.container = this.widget; this.createGauges(); this.createNetworkChart(); this.createCpuChart(); this.createMemoryChart(); this.createNetworkStatsBox(); this.createProcessStatsBox(); this.createInfoBox(); this.createAlertBox(); this.startDataCollection(); } catch (error) { this.handleResourceError(error instanceof Error ? error : new Error('Widget creation failed')); } } createGauges() { this.cpuGauge = contrib.gauge({ top: '1%', left: '0%', width: '33%', height: '40%', label: 'CPU Usage', stroke: 'green', fill: 'white', showLabel: true, style: { label: { fg: 'white' }, }, }); this.container.append(this.cpuGauge); this.memoryGauge = contrib.gauge({ top: '1%', left: '33%', width: '33%', height: '40%', label: 'Memory Usage', stroke: 'green', fill: 'white', showLabel: true, style: { label: { fg: 'white' }, }, }); this.container.append(this.memoryGauge); this.processGauge = contrib.gauge({ top: '1%', left: '66%', width: '34%', height: '40%', label: 'Process CPU', stroke: 'green', fill: 'white', showLabel: true, style: { label: { fg: 'white' }, }, }); this.container.append(this.processGauge); } createNetworkChart() { this.networkChart = contrib.line({ label: 'Network Traffic (MB/s)', showLegend: true, legend: { width: 12 }, style: { line: 'yellow', text: 'green', baseline: 'black', }, }); this.networkChart.top = '41%'; this.networkChart.left = '0%'; this.networkChart.width = '35%'; this.networkChart.height = '25%'; this.container.append(this.networkChart); } createCpuChart() { this.cpuChart = contrib.line({ label: 'CPU Usage Trend (%)', showLegend: false, style: { line: 'red', text: 'green', baseline: 'black', }, }); this.cpuChart.top = '41%'; this.cpuChart.left = '35%'; this.cpuChart.width = '35%'; this.cpuChart.height = '25%'; this.container.append(this.cpuChart); } createMemoryChart() { this.memoryChart = contrib.line({ label: 'Memory Usage Trend (%)', showLegend: false, style: { line: 'blue', text: 'green', baseline: 'black', }, }); this.memoryChart.top = '66%'; this.memoryChart.left = '0%'; this.memoryChart.width = '35%'; this.memoryChart.height = '25%'; this.container.append(this.memoryChart); } createNetworkStatsBox() { this.networkStatsBox = blessed.box({ parent: this.container, top: '41%', left: '70%', width: '30%', height: '25%', label: ' Network Stats ', border: { type: 'line' }, style: { border: { fg: 'cyan' }, label: { fg: 'white' }, }, content: 'Loading network stats...', }); } createProcessStatsBox() { this.processStatsBox = blessed.box({ parent: this.container, top: '66%', left: '35%', width: '35%', height: '25%', label: ' Process Stats ', border: { type: 'line' }, style: { border: { fg: 'magenta' }, label: { fg: 'white' }, }, content: 'Loading process stats...', }); } createInfoBox() { this.infoBox = blessed.box({ parent: this.container, top: '91%', left: 0, width: '50%', height: '9%', label: ' System Info ', border: { type: 'line' }, style: { border: { fg: 'gray' }, label: { fg: 'white' }, }, content: 'Loading system info...', }); } createAlertBox() { this.alertBox = blessed.box({ parent: this.container, top: '91%', left: '50%', width: '50%', height: '9%', label: ' Alerts ', border: { type: 'line' }, style: { border: { fg: 'red' }, label: { fg: 'white' }, }, content: 'No alerts', }); } startDataCollection() { this.collectResourceData(); const refreshInterval = this.config.config['refreshInterval'] || 5000; this.startRefresh(refreshInterval); } async collectResourceData() { try { await this.systemResourceService.getSystemResources(); } catch (error) { this.handleResourceError(error instanceof Error ? error : new Error('Data collection failed')); } } updateNetworkHistory(resources) { const now = Date.now(); const currentBytes = { in: resources.network.totalBytesIn, out: resources.network.totalBytesOut, timestamp: now, }; let inRate = 0; let outRate = 0; if (this.lastNetworkBytes.timestamp > 0) { const timeDiff = (now - this.lastNetworkBytes.timestamp) / 1000; if (timeDiff > 0) { inRate = Math.max(0, (currentBytes.in - this.lastNetworkBytes.in) / timeDiff); outRate = Math.max(0, (currentBytes.out - this.lastNetworkBytes.out) / timeDiff); } } this.lastNetworkBytes = currentBytes; this.networkHistory.push({ timestamp: now, bytesIn: inRate / (1024 * 1024), bytesOut: outRate / (1024 * 1024), }); if (this.networkHistory.length > this.maxNetworkHistorySize) { this.networkHistory.shift(); } } updateCpuHistory(resources) { const now = Date.now(); this.cpuHistory.push({ timestamp: now, usage: resources.cpu.usage, }); if (this.cpuHistory.length > this.maxCpuHistorySize) { this.cpuHistory.shift(); } } updateMemoryHistory(resources) { const now = Date.now(); this.memoryHistory.push({ timestamp: now, usage: resources.memory.percentage, }); if (this.memoryHistory.length > this.maxMemoryHistorySize) { this.memoryHistory.shift(); } } handleResourceError(error) { if (!this.isGracefullyDegraded) { this.isGracefullyDegraded = true; this.showDegradedMode(); } this.handleError(error); } showDegradedMode() { if (this.alertBox) { this.alertBox.setContent('DEGRADED MODE\nLimited data available'); this.alertBox.style.border = { fg: 'yellow' }; } } render() { if (!this.currentResources) return; try { this.updateGauges(); this.updateNetworkChart(); this.updateCpuChart(); this.updateMemoryChart(); this.updateNetworkStatsBox(); this.updateProcessStatsBox(); this.updateInfoBox(); this.updateAlertBox(); const currentScreen = getScreen(); if (currentScreen && currentScreen.render) { currentScreen.render(); } } catch (error) { this.handleError(error instanceof Error ? error : new Error('Render failed')); } } updateGauges() { if (!this.currentResources) return; if (this.cpuGauge) { const cpuPercent = this.currentResources.cpu.usage; this.cpuGauge.setPercent(cpuPercent); this.cpuGauge.setStack([ { percent: cpuPercent, stroke: this.getColorForValue(cpuPercent, 'cpu') } ]); } if (this.memoryGauge) { const memoryPercent = this.currentResources.memory.percentage; this.memoryGauge.setPercent(memoryPercent); this.memoryGauge.setStack([ { percent: memoryPercent, stroke: this.getColorForValue(memoryPercent, 'memory') } ]); } if (this.processGauge) { const processPercent = Math.min(100, this.currentResources.process.cpuUsage); this.processGauge.setPercent(processPercent); const ratingColor = this.currentResources.process.performanceRating === 'excellent' ? 'green' : this.currentResources.process.performanceRating === 'good' ? 'cyan' : this.currentResources.process.performanceRating === 'fair' ? 'yellow' : 'red'; this.processGauge.setStack([ { percent: processPercent, stroke: ratingColor } ]); } } updateNetworkChart() { if (!this.networkChart || this.networkHistory.length === 0) return; const labels = this.networkHistory.map((_, index) => index.toString()); const inData = this.networkHistory.map(entry => entry.bytesIn.toFixed(2)); const outData = this.networkHistory.map(entry => entry.bytesOut.toFixed(2)); this.networkChart.setData([ { title: 'In', x: labels, y: inData, style: { line: 'green' }, }, { title: 'Out', x: labels, y: outData, style: { line: 'red' }, }, ]); } updateCpuChart() { if (!this.cpuChart || this.cpuHistory.length === 0) return; const labels = this.cpuHistory.map((_, index) => index.toString()); const data = this.cpuHistory.map(entry => entry.usage.toFixed(1)); this.cpuChart.setData([ { title: 'CPU', x: labels, y: data, style: { line: 'red' }, }, ]); } updateMemoryChart() { if (!this.memoryChart || this.memoryHistory.length === 0) return; const labels = this.memoryHistory.map((_, index) => index.toString()); const data = this.memoryHistory.map(entry => entry.usage.toFixed(1)); this.memoryChart.setData([ { title: 'Memory', x: labels, y: data, style: { line: 'blue' }, }, ]); } updateNetworkStatsBox() { if (!this.networkStatsBox || !this.currentResources) return; const network = this.currentResources.network; const totalRateIn = network.totalRateIn || 0; const totalRateOut = network.totalRateOut || 0; const totalRate = totalRateIn + totalRateOut; const bandwidthIn = system_resource_service_1.NetworkUtils.formatBandwidth(totalRateIn); const bandwidthOut = system_resource_service_1.NetworkUtils.formatBandwidth(totalRateOut); const totalBandwidth = system_resource_service_1.NetworkUtils.formatBandwidth(totalRate); const totalBytes = system_resource_service_1.NetworkUtils.formatBytes(network.totalBytesIn + network.totalBytesOut); const content = [ `Total: ${totalBandwidth.formatted}`, `In: ${bandwidthIn.formatted}`, `Out: ${bandwidthOut.formatted}`, ``, `Total Data: ${totalBytes.formatted}`, `Active IFs: ${network.activeInterfaces}`, `Connections: ${network.connections}`, `State: ${network.connectionState}`, ``, `Interface Details:`, ...network.interfaces.slice(0, 3).map(iface => ` ${iface.name}: ${iface.isUp ? 'UP' : 'DOWN'}`), ].join('\n'); this.networkStatsBox.setContent(content); const borderColor = network.connectionState === 'connected' ? 'green' : network.connectionState === 'limited' ? 'yellow' : 'red'; this.networkStatsBox.style.border = { fg: borderColor }; } updateProcessStatsBox() { if (!this.processStatsBox || !this.currentResources) return; const proc = this.currentResources.process; const uptimeHours = Math.floor(proc.uptime / 3600); const uptimeMinutes = Math.floor((proc.uptime % 3600) / 60); const uptimeSeconds = Math.floor(proc.uptime % 60); const uptimeFormatted = `${uptimeHours}h ${uptimeMinutes}m ${uptimeSeconds}s`; const heapUsed = system_resource_service_1.NetworkUtils.formatBytes(proc.heapUsed); const heapTotal = system_resource_service_1.NetworkUtils.formatBytes(proc.heapTotal || 0); const rss = system_resource_service_1.NetworkUtils.formatBytes(proc.rss || 0); const peakMemory = system_resource_service_1.NetworkUtils.formatBytes(proc.peakMemoryUsage || 0); const ratingColor = proc.performanceRating === 'excellent' ? 'green' : proc.performanceRating === 'good' ? 'cyan' : proc.performanceRating === 'fair' ? 'yellow' : 'red'; const content = [ `PID: ${proc.pid}`, `Status: ${proc.status}`, `Uptime: ${uptimeFormatted}`, ``, `CPU: ${proc.cpuUsage}%`, `Avg CPU: ${proc.avgCpuUsage || 0}%`, ``, `Heap: ${heapUsed.formatted}`, `Total: ${heapTotal.formatted}`, `RSS: ${rss.formatted}`, `Peak: ${peakMemory.formatted}`, ``, `FDs: ${proc.fileDescriptors || 'N/A'}`, `Threads: ${proc.threadCount || 'N/A'}`, ``, `Rating: ${proc.performanceRating || 'unknown'}`, ].join('\n'); this.processStatsBox.setContent(content); this.processStatsBox.style.border = { fg: ratingColor }; } updateInfoBox() { if (!this.infoBox || !this.currentResources) return; const info = this.systemResourceService.getSystemInfo(); const formatBytes = (bytes) => { const result = system_resource_service_1.NetworkUtils.formatBytes(bytes); return result.formatted; }; const content = [ `Platform: ${info.platform}`, `Hostname: ${info.hostname}`, `Uptime: ${Math.floor(info.uptime / 3600)}h ${Math.floor((info.uptime % 3600) / 60)}m`, `Memory: ${formatBytes(this.currentResources.memory.used)} / ${formatBytes(this.currentResources.memory.total)}`, `CPU: ${this.currentResources.cpu.cores} cores`, `Process: PID ${this.currentResources.process.pid}`, `Proc Mem: ${formatBytes(this.currentResources.process.memoryUsage)}`, ].join('\n'); this.infoBox.setContent(content); } updateAlertBox() { if (!this.alertBox || !this.currentResources) return; const alerts = []; if (this.currentResources.cpu.usage >= this.alertThresholds.cpu.critical) { alerts.push(`CPU: ${this.currentResources.cpu.usage}% (CRITICAL)`); } else if (this.currentResources.cpu.usage >= this.alertThresholds.cpu.warning) { alerts.push(`CPU: ${this.currentResources.cpu.usage}% (WARNING)`); } if (this.currentResources.memory.percentage >= this.alertThresholds.memory.critical) { alerts.push(`Memory: ${this.currentResources.memory.percentage}% (CRITICAL)`); } else if (this.currentResources.memory.percentage >= this.alertThresholds.memory.warning) { alerts.push(`Memory: ${this.currentResources.memory.percentage}% (WARNING)`); } const currentNetworkMBps = this.networkHistory.length > 0 ? (this.networkHistory[this.networkHistory.length - 1]?.bytesIn || 0) + (this.networkHistory[this.networkHistory.length - 1]?.bytesOut || 0) : 0; if (currentNetworkMBps >= this.alertThresholds.network.critical) { alerts.push(`Network: ${currentNetworkMBps.toFixed(1)}MB/s (CRITICAL)`); } else if (currentNetworkMBps >= this.alertThresholds.network.warning) { alerts.push(`Network: ${currentNetworkMBps.toFixed(1)}MB/s (WARNING)`); } const content = alerts.length > 0 ? alerts.join('\n') : 'No alerts'; this.alertBox.setContent(content); if (alerts.some(alert => alert.includes('CRITICAL'))) { this.alertBox.style.border = { fg: 'red' }; } else if (alerts.some(alert => alert.includes('WARNING'))) { this.alertBox.style.border = { fg: 'yellow' }; } else { this.alertBox.style.border = { fg: 'green' }; } } getColorForValue(value, type) { const thresholds = this.alertThresholds[type]; if (value >= thresholds.critical) { return 'red'; } else if (value >= thresholds.warning) { return 'yellow'; } else { return 'green'; } } update(data) { if (this.isDestroyed) return; try { this.currentResources = data; this.updateState({ data, lastUpdate: new Date() }); this.throttledRender(); } catch (error) { this.handleError(error instanceof Error ? error : new Error('Update failed')); } } requestUpdate() { this.collectResourceData(); } destroy() { if (this.systemResourceService) { this.systemResourceService.removeAllListeners(); } this.networkHistory = []; this.cpuHistory = []; this.memoryHistory = []; this.currentResources = null; super.destroy(); } } exports.SystemResourcePanel = SystemResourcePanel; //# sourceMappingURL=system-resource.panel.js.map