namespace Rainbow.Services;
/// <summary>系统监控数æ®é‡‡é›†å™¨ã€‚委托给 IOSAdapter 采集 CPU/内å˜/è¿è¡Œæ—¶é—´/连接数,委托给 INetworkStatProvider é‡‡é›†ç½‘å£æµé‡</summary>
public class MonitorCollector
{
private readonly IOSAdapter _osAdapter;
private readonly INetworkStatProvider? _networkStatProvider;
private Dictionary<String, NetworkStats> _lastStats = new();
private DateTime _lastCollectTime = DateTime.MinValue;
/// <summary>æž„é€ ç›‘æŽ§é‡‡é›†å™¨</summary>
/// <param name="osAdapter">æ“作系统适é…器</param>
/// <param name="networkStatProvider">ç½‘å£æµé‡ç»Ÿè®¡æä¾›è€…(å¯é€‰ï¼ŒWindows 上由 DI 注入,Linux 上由 DebianAdapter æä¾›ï¼‰</param>
public MonitorCollector(IOSAdapter osAdapter, INetworkStatProvider? networkStatProvider = null)
{
_osAdapter = osAdapter ?? throw new ArgumentNullException(nameof(osAdapter));
_networkStatProvider = networkStatProvider;
}
/// <summary>èŽ·å– CPU 使用率(委托给 IOSAdapter)</summary>
public Double GetCpuUsage() => _osAdapter.GetCpuUsage();
/// <summary>获å–内å˜ä½¿ç”¨çŽ‡ï¼ˆå§”æ‰˜ç»™ IOSAdapter)</summary>
public Double GetMemoryUsage() => _osAdapter.GetMemoryUsage();
/// <summary>获å–ç£ç›˜ä½¿ç”¨çŽ‡ï¼ˆå§”æ‰˜ç»™ IOSAdapter)</summary>
public Double GetDiskUsage() => _osAdapter.GetDiskUsage();
/// <summary>获å–系统信æ¯ï¼ˆå§”托给 IOSAdapter)</summary>
public SystemInfo GetSystemInfo() => _osAdapter.GetSystemInfo();
/// <summary>获å–系统è¿è¡Œæ—¶é—´ï¼ˆå§”托给 IOSAdapter)</summary>
public Int64 GetUptimeSeconds() => _osAdapter.GetUptimeSeconds();
/// <summary>获å–网络连接数(委托给 IOSAdapter)</summary>
public Int32 GetConnectionCount() => _osAdapter.GetConnectionCount();
/// <summary>获å–ç½‘å£æµé‡ç»Ÿè®¡ã€‚优先委托给 INetworkStatProvider,ä¸å¯ç”¨æ—¶å›žé€€è¯»å– /proc/net/dev</summary>
public async Task<List<NetworkStats>> GetNetworkStatsAsync()
{
if (_networkStatProvider != null)
{
var stats = await _networkStatProvider.GetInterfaceStatsAsync();
return ConvertToNetworkStats(stats);
}
// å›žé€€ï¼šç›´æŽ¥è¯»å– /proc/net/dev(仅 Linux)
return await GetNetworkStatsFromProcAsync();
}
private List<NetworkStats> ConvertToNetworkStats(List<InterfaceStatData> stats)
{
var result = new List<NetworkStats>();
var now = DateTime.Now;
var elapsed = _lastCollectTime != DateTime.MinValue ? (now - _lastCollectTime).TotalSeconds : 1;
foreach (var s in stats)
{
var ns = new NetworkStats
{
InterfaceName = s.Name,
RxBytes = s.RxBytes,
TxBytes = s.TxBytes,
};
if (_lastStats.TryGetValue(s.Name, out var last))
{
ns.RxSpeed = (Int64)((ns.RxBytes - last.RxBytes) / elapsed);
ns.TxSpeed = (Int64)((ns.TxBytes - last.TxBytes) / elapsed);
}
result.Add(ns);
_lastStats[s.Name] = ns;
}
_lastCollectTime = now;
return result;
}
private async Task<List<NetworkStats>> GetNetworkStatsFromProcAsync()
{
var result = new List<NetworkStats>();
if (!OperatingSystem.IsLinux()) return result;
try
{
var lines = await Task.Run(() => File.ReadAllLines("/proc/net/dev"));
var now = DateTime.Now;
var elapsed = _lastCollectTime != DateTime.MinValue ? (now - _lastCollectTime).TotalSeconds : 1;
for (var i = 2; i < lines.Length; i++)
{
var line = lines[i].Trim();
var idx = line.IndexOf(':');
if (idx < 0) continue;
var ifName = line.Substring(0, idx).Trim();
var parts = line.Substring(idx + 1).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length < 10) continue;
var stats = new NetworkStats
{
InterfaceName = ifName,
RxBytes = Int64.Parse(parts[0]),
TxBytes = Int64.Parse(parts[8]),
};
if (_lastStats.TryGetValue(ifName, out var last))
{
stats.RxSpeed = (Int64)((stats.RxBytes - last.RxBytes) / elapsed);
stats.TxSpeed = (Int64)((stats.TxBytes - last.TxBytes) / elapsed);
}
result.Add(stats);
_lastStats[ifName] = stats;
}
_lastCollectTime = now;
}
catch { }
return result;
}
}
|