node-os-utils
Version:
Advanced cross-platform operating system monitoring utilities with TypeScript support
586 lines • 22.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NetworkMonitor = void 0;
const base_monitor_1 = require("../core/base-monitor");
const types_1 = require("../types");
/**
* 网络监控器
*
* 提供网络相关的监控功能,包括接口信息、流量统计、连接状态等
*/
class NetworkMonitor extends base_monitor_1.BaseMonitor {
// private previousStats: Map<string, NetworkStats> = new Map();
// private lastStatsTime: number = 0;
constructor(adapter, config = {}, cache) {
super(adapter, config, cache);
this.networkConfig = { ...this.getDefaultConfig(), ...config };
}
/**
* 获取网络接口信息(实现抽象方法)
*/
async info() {
return this.interfaces();
}
/**
* 获取网络接口信息
*/
async interfaces() {
const cacheKey = 'network-interfaces';
return this.executeWithCache(cacheKey, async () => {
this.validatePlatformSupport('network.interfaces');
const rawData = await this.adapter.getNetworkInterfaces();
return this.transformNetworkInterfaces(rawData);
}, this.networkConfig.cacheTTL || 10000);
}
/**
* 获取指定接口信息
*/
async interfaceByName(name) {
const interfacesResult = await this.interfaces();
if (!interfacesResult.success || !interfacesResult.data) {
return interfacesResult;
}
const networkInterface = interfacesResult.data.find(iface => iface.name === name);
return this.createSuccessResult(networkInterface || null);
}
/**
* 获取网络统计信息(异步版本)
*/
async statsAsync(options = {}) {
if (!this.networkConfig.includeInterfaceStats) {
return this.createErrorResult(this.createUnsupportedError('network.stats (disabled in config)'));
}
const cacheKey = 'network-stats';
const fetchStats = async () => {
this.validatePlatformSupport('network.stats');
const rawData = await this.adapter.getNetworkStats();
return this.transformNetworkStats(rawData);
};
if (options.skipCache) {
try {
const data = await fetchStats();
return this.createSuccessResult(data, false);
}
catch (error) {
return this.handleError(error);
}
}
return this.executeWithCache(cacheKey, fetchStats, this.networkConfig.cacheTTL || 2000 // 统计信息缓存较短
);
}
/**
* 获取指定接口的统计信息
*/
async statsByInterface(interfaceName) {
const statsResult = await this.statsAsync();
if (!statsResult.success || !statsResult.data) {
return statsResult;
}
const stats = statsResult.data.find(stat => stat.interface === interfaceName);
return this.createSuccessResult(stats || null);
}
/**
* 获取带宽使用情况(需要两次测量)
*/
async bandwidth() {
if (!this.networkConfig.includeBandwidth) {
return this.createErrorResult(this.createUnsupportedError('network.bandwidth (disabled in config)'));
}
const interval = this.networkConfig.bandwidthInterval || 1000;
// 第一次测量
const firstStatsResult = await this.statsAsync({ skipCache: true });
if (!firstStatsResult.success || !firstStatsResult.data) {
throw new Error('Failed to get network stats for bandwidth calculation');
}
// 等待指定间隔
await new Promise(resolve => setTimeout(resolve, interval));
// 第二次测量
const secondStatsResult = await this.statsAsync({ skipCache: true });
if (!secondStatsResult.success || !secondStatsResult.data) {
throw new Error('Failed to get second network stats for bandwidth calculation');
}
// 计算带宽
const bandwidth = this.calculateBandwidth(firstStatsResult.data, secondStatsResult.data, interval);
return this.createSuccessResult({
interval,
interfaces: bandwidth
});
}
/**
* 获取活跃的网络连接
*/
async connections() {
if (!this.networkConfig.includeConnections) {
return this.createErrorResult(this.createUnsupportedError('network.connections (disabled in config)'));
}
const cacheKey = 'network-connections';
return this.executeWithCache(cacheKey, async () => {
this.validatePlatformSupport('network.connections');
const rawData = await this.adapter.getNetworkConnections();
return this.transformNetworkConnections(rawData);
}, this.networkConfig.cacheTTL || 5000);
}
/**
* 获取默认网关信息
*/
async gateway() {
const cacheKey = 'network-gateway';
return this.executeWithCache(cacheKey, async () => {
this.validatePlatformSupport('network.gateway');
const rawData = await this.adapter.getDefaultGateway();
return this.transformGatewayInfo(rawData);
}, this.networkConfig.cacheTTL || 30000);
}
/**
* 获取公网 IP 地址
*/
async publicIP() {
const cacheKey = 'network-public-ip';
return this.executeWithCache(cacheKey, async () => {
// 这个功能可能需要外部服务,暂时返回空结果
return {
ipv4: undefined,
ipv6: undefined
};
}, this.networkConfig.cacheTTL || 300000 // 公网 IP 缓存 5 分钟
);
}
/**
* 网络健康检查
*/
async healthCheck() {
const cacheKey = 'network-health';
return this.executeWithCache(cacheKey, async () => {
const issues = [];
const checks = {
interfaceStatus: true,
connectivity: true,
performance: true
};
// 检查网络接口状态
try {
const interfacesResult = await this.interfaces();
if (interfacesResult.success && interfacesResult.data) {
const activeInterfaces = interfacesResult.data.filter(iface => iface.state === 'up' && !iface.internal);
if (activeInterfaces.length === 0) {
issues.push('No active network interfaces found');
checks.interfaceStatus = false;
}
// 检查是否有错误率高的接口
if (this.networkConfig.includeInterfaceStats) {
const statsResult = await this.statsAsync();
if (statsResult.success && statsResult.data) {
for (const stats of statsResult.data) {
const totalPackets = stats.rxPackets + stats.txPackets;
const totalErrors = stats.rxErrors + stats.txErrors;
const errorRate = totalPackets > 0 ? (totalErrors / totalPackets) * 100 : 0;
if (errorRate > 5) {
issues.push(`High error rate on interface ${stats.interface}: ${errorRate.toFixed(2)}%`);
checks.performance = false;
}
}
}
}
}
}
catch (error) {
issues.push('Failed to check network interface status');
checks.interfaceStatus = false;
}
// 检查默认网关连通性
try {
const gatewayResult = await this.gateway();
if (!gatewayResult.success || !gatewayResult.data) {
issues.push('No default gateway configured');
checks.connectivity = false;
}
}
catch (error) {
issues.push('Failed to get gateway information');
checks.connectivity = false;
}
// 确定整体健康状态
let status = 'healthy';
if (!checks.interfaceStatus || !checks.connectivity) {
status = 'critical';
}
else if (!checks.performance || issues.length > 0) {
status = 'warning';
}
return {
status,
issues,
checks
};
}, this.networkConfig.cacheTTL || 30000);
}
/**
* 获取网络总览信息
*/
async overview() {
const cacheKey = 'network-overview';
return this.executeWithCache(cacheKey, async () => {
const [interfacesResult, statsResult] = await Promise.all([
this.interfaces(),
this.statsAsync().catch(() => ({ success: false, data: null }))
]);
if (!interfacesResult.success || !interfacesResult.data) {
throw new Error('Failed to get network interfaces');
}
const interfaces = interfacesResult.data;
const activeInterfaces = interfaces.filter(iface => iface.state === 'up' && !iface.internal).length;
let totalRxBytes = 0;
let totalTxBytes = 0;
let totalPackets = 0;
let totalErrors = 0;
if (statsResult.success && statsResult.data) {
for (const stats of statsResult.data) {
totalRxBytes += stats.rxBytes.toBytes();
totalTxBytes += stats.txBytes.toBytes();
totalPackets += stats.rxPackets + stats.txPackets;
totalErrors += stats.rxErrors + stats.txErrors;
}
}
return {
interfaces: interfaces.length,
activeInterfaces,
totalRxBytes: new types_1.DataSize(totalRxBytes),
totalTxBytes: new types_1.DataSize(totalTxBytes),
totalPackets,
totalErrors
};
}, this.networkConfig.cacheTTL || 10000);
}
/**
* 配置是否包含接口统计
*/
withInterfaceStats(include) {
this.networkConfig.includeInterfaceStats = include;
return this;
}
/**
* 配置是否包含连接信息
*/
withConnections(include) {
this.networkConfig.includeConnections = include;
return this;
}
/**
* 配置是否包含带宽监控
*/
withBandwidth(include) {
this.networkConfig.includeBandwidth = include;
return this;
}
/**
* 配置目标网络接口
*/
withInterfaces(interfaces) {
this.networkConfig.interfaces = interfaces;
return this;
}
/**
* 配置带宽监控间隔
*/
withBandwidthInterval(interval) {
this.networkConfig.bandwidthInterval = interval;
return this;
}
/**
* 获取默认配置
*/
getDefaultConfig() {
return {
interval: 2000,
timeout: 10000,
cacheEnabled: true,
cacheTTL: 5000,
samples: 1,
includeDetails: true,
includeInterfaceStats: true,
includeConnections: false, // 连接信息可能较多,默认不包含
includeBandwidth: false, // 带宽监控需要额外计算,默认不包含
bandwidthInterval: 1000,
unit: 'auto'
};
}
// 私有转换方法
/**
* 转换网络接口信息
*/
/**
* 将平台适配器返回的原始接口数据统一转换为 NetworkInterface 结构
* 支持 Node.js os.networkInterfaces() 返回的对象以及适配器自定义的数组格式
*/
transformNetworkInterfaces(rawData) {
if (!rawData) {
return [];
}
/**
* 收集单个网卡的信息并写入结果数组
*/
const addInterface = (name, addresses, raw) => {
if (!Array.isArray(addresses) || addresses.length === 0) {
return;
}
const transformedAddresses = addresses.map((addr) => ({
address: addr.address || '',
netmask: addr.netmask || '',
family: addr.family === 'IPv6' || addr.family === 6 ? 'IPv6' : 'IPv4',
internal: addr.internal || false,
scopeid: addr.scopeid
}));
const firstAddr = addresses[0];
const rawState = raw?.state ?? raw?.operstate ?? raw?.status;
const networkInterface = {
name,
addresses: transformedAddresses,
mac: firstAddr?.mac || '',
state: this.normalizeInterfaceState(rawState, firstAddr),
type: this.inferInterfaceType(name),
mtu: firstAddr?.mtu || 1500,
internal: Boolean(raw?.internal ?? firstAddr?.internal ?? false),
speed: firstAddr?.speed,
duplex: firstAddr?.duplex
};
if (this.shouldIncludeInterface(networkInterface)) {
interfaces.push(networkInterface);
}
};
const interfaces = [];
if (Array.isArray(rawData)) {
for (const item of rawData) {
if (!item || typeof item !== 'object')
continue;
const name = item.name || item.interface;
if (!name)
continue;
const addresses = Array.isArray(item.addresses)
? item.addresses
: [{
address: item.address,
netmask: item.netmask,
family: item.family,
internal: item.internal,
mac: item.mac,
mtu: item.mtu,
scopeid: item.scopeid
}];
addInterface(name, addresses, item);
}
return interfaces;
}
if (typeof rawData === 'object') {
for (const [name, addresses] of Object.entries(rawData)) {
addInterface(name, addresses, rawData[name]);
}
}
return interfaces;
}
/**
* 转换网络统计信息
*/
transformNetworkStats(rawData) {
if (!Array.isArray(rawData)) {
return [];
}
return rawData
.filter(stats => this.shouldIncludeInterface({ name: stats.interface }))
.map(stats => ({
interface: stats.interface || stats.name || 'unknown',
rxBytes: new types_1.DataSize(this.safeParseNumber(stats.rxBytes || stats.rx_bytes)),
txBytes: new types_1.DataSize(this.safeParseNumber(stats.txBytes || stats.tx_bytes)),
rxPackets: this.safeParseNumber(stats.rxPackets || stats.rx_packets),
txPackets: this.safeParseNumber(stats.txPackets || stats.tx_packets),
rxErrors: this.safeParseNumber(stats.rxErrors || stats.rx_errors),
txErrors: this.safeParseNumber(stats.txErrors || stats.tx_errors),
rxDropped: this.safeParseNumber(stats.rxDropped || stats.rx_dropped),
txDropped: this.safeParseNumber(stats.txDropped || stats.tx_dropped),
rxSpeed: stats.rxSpeed,
txSpeed: stats.txSpeed
}));
}
/**
* 转换网络连接信息
*/
transformNetworkConnections(rawData) {
if (!Array.isArray(rawData)) {
return [];
}
return rawData.map(conn => ({
protocol: conn.protocol || 'unknown',
localAddress: conn.localAddress || conn.local_address,
localPort: conn.localPort || conn.local_port,
remoteAddress: conn.remoteAddress || conn.remote_address,
remotePort: conn.remotePort || conn.remote_port,
state: conn.state || 'unknown',
pid: conn.pid
}));
}
/**
* 转换网关信息
*/
transformGatewayInfo(rawData) {
// 网关信息在 Linux 点对点链路中可能只有接口(例如 `default dev ppp0`),此时仍视为有效路由
if (!rawData || (rawData.gateway == null && rawData.interface == null && rawData.iface == null && rawData.device == null)) {
return null;
}
return {
// 优先使用显式网关地址,若缺失则回退到 `address` 字段,保持与适配器输出一致
gateway: rawData.gateway ?? rawData.address ?? null,
// 兼容不同平台字段命名(interface/iface/device),确保能准确识别默认出口
interface: rawData.interface || rawData.iface || rawData.device || 'unknown'
};
}
/**
* 计算带宽
*/
calculateBandwidth(firstStats, secondStats, intervalMs) {
const results = [];
for (const firstStat of firstStats) {
const secondStat = secondStats.find(s => s.interface === firstStat.interface);
if (!secondStat)
continue;
const intervalSec = intervalMs / 1000;
const rxDiff = secondStat.rxBytes.toBytes() - firstStat.rxBytes.toBytes();
const txDiff = secondStat.txBytes.toBytes() - firstStat.txBytes.toBytes();
const rxSpeed = Math.max(0, rxDiff / intervalSec); // 字节/秒
const txSpeed = Math.max(0, txDiff / intervalSec); // 字节/秒
results.push({
interface: firstStat.interface,
rxSpeed,
txSpeed,
rxSpeedFormatted: new types_1.DataSize(rxSpeed).toString(this.networkConfig.unit || 'auto') + '/s',
txSpeedFormatted: new types_1.DataSize(txSpeed).toString(this.networkConfig.unit || 'auto') + '/s'
});
}
return results;
}
/**
* 推断接口状态
*/
inferInterfaceState(addr) {
// 如果有地址且不是内部接口,通常表示接口是活跃的
if (addr && addr.address && !addr.internal) {
return 'up';
}
// 内部接口(如回环)通常也是活跃的
if (addr && addr.internal && addr.address) {
return 'up';
}
return 'unknown';
}
/**
* 推断接口类型
*/
inferInterfaceType(name) {
const lowerName = name.toLowerCase();
if (lowerName.includes('lo') || lowerName.includes('loopback')) {
return 'loopback';
}
if (lowerName.includes('wifi') || lowerName.includes('wlan') || lowerName.includes('wireless')) {
return 'wifi';
}
if (lowerName.includes('eth') || lowerName.includes('en')) {
return 'ethernet';
}
if (lowerName.includes('virt') || lowerName.includes('docker') || lowerName.includes('br-')) {
return 'virtual';
}
return 'other';
}
/**
* 判断是否应该包含该接口
*/
shouldIncludeInterface(networkInterface) {
// 如果配置了特定接口列表,只包含这些接口
if (this.networkConfig.interfaces && this.networkConfig.interfaces.length > 0) {
return this.networkConfig.interfaces.includes(networkInterface.name);
}
return true;
}
normalizeInterfaceState(rawState, addr) {
// 直接复用适配器给出的状态,若不存在则回退到地址推断以保留兼容性
if (typeof rawState === 'string') {
const normalized = rawState.toLowerCase();
if (/(up|running|active|online)/.test(normalized)) {
return 'up';
}
if (/(down|inactive|disabled|offline)/.test(normalized)) {
return 'down';
}
}
return this.inferInterfaceState(addr);
}
/**
* 安全解析数字
*/
safeParseNumber(value) {
if (typeof value === 'number') {
return isNaN(value) ? 0 : value;
}
if (typeof value === 'string') {
const parsed = parseFloat(value);
return isNaN(parsed) ? 0 : parsed;
}
return 0;
}
// ==================== 向后兼容的同步方法 ====================
/**
* 获取网络流量统计(同步版本,向后兼容)
* @param interval 监控间隔(毫秒)
* @returns 网络流量统计对象或 'not supported'
*/
inOut(interval = 1000) {
try {
// 对于同步版本,无法进行实际的网络监控
// 返回基本结构,实际值需要通过异步方法获取
return {
total: {
inputMb: 0,
outputMb: 0
},
inputMb: 0,
outputMb: 0
};
}
catch (error) {
return 'not supported';
}
}
/**
* 获取网络统计信息(同步版本,向后兼容)
* @returns 网络统计信息数组或 'not supported'
*/
stats() {
try {
// 对于同步版本,返回基本的网络接口信息
const os = require('os');
const interfaces = os.networkInterfaces();
const result = [];
for (const [name, addresses] of Object.entries(interfaces)) {
if (Array.isArray(addresses) && addresses.length > 0) {
const addr = addresses[0];
result.push({
iface: name,
operstate: addr.internal ? 'down' : 'up',
rx_bytes: 0,
rx_dropped: 0,
rx_errors: 0,
tx_bytes: 0,
tx_dropped: 0,
tx_errors: 0,
internal: addr.internal,
address: addr.address
});
}
}
return result;
}
catch (error) {
return 'not supported';
}
}
}
exports.NetworkMonitor = NetworkMonitor;
//# sourceMappingURL=network-monitor.js.map