refactor: 枚举移入Models目录,命名空间更新为Rainbow.Entity.Models
大石头 authored at 2026-07-02 12:54:58
4.67 KiB
RainbowBridge
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;
    }
}