refactor: 枚举移入Models目录,命名空间更新为Rainbow.Entity.Models
大石头 authored at 2026-07-02 12:54:58
6.11 KiB
RainbowBridge
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace Rainbow.Services;

/// <summary>Windows 适配器。基础 CRUD 能力,系统信息采集用 .NET 内置 API + P/Invoke</summary>
public class WindowsAdapter : IOSAdapter
{
    #region P/Invoke
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern Boolean GetSystemTimes(out FILETIME idleTime, out FILETIME kernelTime, out FILETIME userTime);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern Boolean GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);

    [StructLayout(LayoutKind.Sequential)]
    private struct FILETIME
    {
        public UInt32 Low;
        public UInt32 High;
        public UInt64 ToUInt64() => ((UInt64)High << 32) | Low;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct MEMORYSTATUSEX
    {
        public UInt32 Length;
        public UInt32 MemoryLoad;
        public UInt64 TotalPhys;
        public UInt64 AvailPhys;
        public UInt64 TotalPageFile;
        public UInt64 AvailPageFile;
        public UInt64 TotalVirtual;
        public UInt64 AvailVirtual;
        public UInt64 AvailExtendedVirtual;
    }
    #endregion

    // CPU 计算的缓存状态
    private UInt64 _prevIdle;
    private UInt64 _prevKernel;
    private UInt64 _prevUser;
    private DateTime _prevCpuTime;

    /// <summary>平台名称</summary>
    public String Platform => "Windows";

    /// <summary>获取系统信息</summary>
    public SystemInfo GetSystemInfo() => new()
    {
        CpuUsage = GetCpuUsage(),
        MemoryUsed = GetMemoryUsed(),
        MemoryTotal = GetMemoryTotal(),
        UptimeSeconds = GetUptimeSeconds(),
        ConnectionCount = GetConnectionCount(),
    };

    /// <summary>获取功能支持度。Windows 支持基础网络功能,不支持 Linux 特有功能</summary>
    public Dictionary<String, Boolean> GetCapabilities() => new()
    {
        ["pppoe"] = false,    // 通过 rasdial 可拨号,但非原生 PPPoE 服务
        ["dhcp"] = true,     // Windows DHCP Server 服务
        ["dnsmasq"] = false, // 无 dnsmasq
        ["iptables"] = false,// 使用 netsh advfirewall
        ["iproute2"] = false,// 使用 route 命令
        ["wireguard"] = false,
        ["vlan"] = false,    // 通过 Hyper-V 虚拟交换机
        ["dpi"] = false,
        ["ids"] = false,
    };

    /// <summary>CPU 使用率(0-100)。通过 P/Invoke GetSystemTimes 计算间隔差异</summary>
    public Double GetCpuUsage()
    {
        if (!GetSystemTimes(out var idle, out var kernel, out var user))
            return 0;

        var now = DateTime.UtcNow;
        var idleVal = idle.ToUInt64();
        var kernelVal = kernel.ToUInt64();
        var userVal = user.ToUInt64();

        // 首次调用时缓存并返回 0
        if (_prevCpuTime == default)
        {
            _prevIdle = idleVal;
            _prevKernel = kernelVal;
            _prevUser = userVal;
            _prevCpuTime = now;
            return 0;
        }

        var elapsed = (now - _prevCpuTime).TotalMilliseconds;
        if (elapsed <= 0) return 0;

        var idleDelta = idleVal - _prevIdle;
        var kernelDelta = kernelVal - _prevKernel;
        var userDelta = userVal - _prevUser;
        var totalDelta = kernelDelta + userDelta;

        _prevIdle = idleVal;
        _prevKernel = kernelVal;
        _prevUser = userVal;
        _prevCpuTime = now;

        if (totalDelta == 0) return 0;

        return Math.Round((1 - (Double)idleDelta / totalDelta) * 100, 1);
    }

    /// <summary>内存使用率(0-100)。通过 P/Invoke GlobalMemoryStatusEx 获取</summary>
    public Double GetMemoryUsage()
    {
        var stat = new MEMORYSTATUSEX();
        stat.Length = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(stat);
        if (!GlobalMemoryStatusEx(ref stat))
            return 0;

        return stat.MemoryLoad;
    }

    /// <summary>已用内存(字节)</summary>
    public Int64 GetMemoryUsed()
    {
        var stat = new MEMORYSTATUSEX();
        stat.Length = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(stat);
        if (!GlobalMemoryStatusEx(ref stat))
            return 0;

        return (Int64)(stat.TotalPhys - stat.AvailPhys);
    }

    /// <summary>总内存(字节)</summary>
    public Int64 GetMemoryTotal()
    {
        var stat = new MEMORYSTATUSEX();
        stat.Length = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(stat);
        if (!GlobalMemoryStatusEx(ref stat))
            return 0;

        return (Int64)stat.TotalPhys;
    }

    /// <summary>磁盘使用率</summary>
    public Double GetDiskUsage()
    {
        try
        {
            var drives = DriveInfo.GetDrives();
            var root = drives.FirstOrDefault(d => d.IsReady && d.Name == "C:\\");
            if (root != null && root.TotalSize > 0)
                return Math.Round((1 - (Double)root.AvailableFreeSpace / root.TotalSize) * 100, 1);
        }
        catch { }
        return 0;
    }

    /// <summary>运行时间。使用 Environment.TickCount64</summary>
    public Int64 GetUptimeSeconds() => NewLife.Runtime.TickCount64 / 1000;

    /// <summary>连接数。通过 netstat -an 解析 ESTABLISHED 状态连接</summary>
    public Int32 GetConnectionCount()
    {
        try
        {
            var psi = new ProcessStartInfo("netstat", "-an")
            {
                RedirectStandardOutput = true,
                UseShellExecute = false,
                CreateNoWindow = true,
            };
            using var proc = Process.Start(psi);
            if (proc == null) return 0;

            var output = proc.StandardOutput.ReadToEnd();
            proc.WaitForExit(5000);

            var count = 0;
            foreach (var line in output.Split('\n'))
            {
                var trimmed = line.Trim();
                // 匹配 ESTABLISHED 状态连接(忽略 [::1] 等 IPv6 回环)
                if (trimmed.Contains("ESTABLISHED") && !trimmed.Contains("[::1]"))
                    count++;
            }
            return count;
        }
        catch
        {
            return 0;
        }
    }
}