diff --git a/system/cpu_linux.go b/system/cpu.go similarity index 87% rename from system/cpu_linux.go rename to system/cpu.go index 247e4d1..3d5b532 100644 --- a/system/cpu_linux.go +++ b/system/cpu.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/oneclickvirt/basics/system/model" + "github.com/oneclickvirt/basics/system/utils" "github.com/shirou/gopsutil/cpu" ) @@ -26,7 +27,9 @@ func checkCPUFeatureLinux(filename string, feature string) (string, bool) { } func checkCPUFeature(filename string, feature string) (string, bool) { - if runtime.GOOS == "linux" { + if runtime.GOOS == "windows" { + return utils.CheckCPUFeatureWindows(filename, feature) + } else if runtime.GOOS == "linux" { return checkCPUFeatureLinux(filename, feature) } return "Unsupported OS", false @@ -65,5 +68,9 @@ func getCpuInfo(ret *model.SystemInfo, cpuType string) (*model.SystemInfo, error if !st { ret.CpuVAH, _ = checkCPUFeature(hypervFeature, "hypervisor") } + // 查询CPU的三缓 + if runtime.GOOS == "windows" { + ret.CpuCache = utils.GetCpuCache() + } return ret, nil } diff --git a/system/host_linux.go b/system/host.go similarity index 77% rename from system/host_linux.go rename to system/host.go index 86a6fd8..436fc69 100644 --- a/system/host_linux.go +++ b/system/host.go @@ -3,15 +3,15 @@ package system import ( "context" "fmt" + "github.com/libp2p/go-nat" + "github.com/oneclickvirt/basics/system/utils" + "github.com/shirou/gopsutil/host" "runtime" "time" - - "github.com/libp2p/go-nat" - "github.com/shirou/gopsutil/host" ) -func getHostInfo() (string, string, string, string, string, string, string, error) { - var Platform, Kernal, Arch, VmType, NatType string +func getHostInfo() (string, string, string, string, string, string, string, string, error) { + var Platform, Kernal, Arch, VmType, NatType, CurrentTimeZone string var cachedBootTime time.Time hi, err := host.Info() if err != nil { @@ -41,6 +41,10 @@ func getHostInfo() (string, string, string, string, string, string, string, erro uptimeDuration -= time.Duration(hours) * time.Hour minutes := int(uptimeDuration.Minutes()) uptimeFormatted := fmt.Sprintf("%d days, %02d hours, %02d minutes", days, hours, minutes) + // windows 查询虚拟化类型 使用 wmic + if VmType == "" && runtime.GOOS == "windows" { + VmType = utils.CheckVMTypeWithWIMC() + } // 查询NAT类型 ctx := context.Background() gateway, err := nat.DiscoverGateway(ctx) @@ -48,5 +52,7 @@ func getHostInfo() (string, string, string, string, string, string, string, erro natType := gateway.Type() NatType = natType } - return cpuType, uptimeFormatted, Platform, Kernal, Arch, VmType, NatType, nil + // 获取当前系统的本地时区 + CurrentTimeZone = utils.GetTimeZone() + return cpuType, uptimeFormatted, Platform, Kernal, Arch, VmType, NatType, CurrentTimeZone, nil } diff --git a/system/load_linux.go b/system/load.go similarity index 86% rename from system/load_linux.go rename to system/load.go index c66a9c6..40658e1 100644 --- a/system/load_linux.go +++ b/system/load.go @@ -2,37 +2,14 @@ package system import ( "bufio" + "github.com/oneclickvirt/basics/system/utils" + "github.com/shirou/gopsutil/load" "os" "runtime" "strconv" "strings" - - "github.com/shirou/gopsutil/load" ) -// 获取系统负载信息 -func getSystemLoad() (float64, float64, float64, error) { - var load1, load5, load15 float64 - var err error - if runtime.GOOS == "linux" { - // 尝试从 /proc/loadavg 文件获取负载信息 - load1, load5, load15, err = getLoadFromProc() - if err != nil { - load1, load5, load15 = 0, 0, 0 - } - } - // 使用 gopsutil 获取负载 - avg, err := load.Avg() - if err != nil { - load1, load5, load15 = 0, 0, 0 - } else { - if avg.Load1 != 0 && avg.Load5 != 0 && avg.Load15 != 0 { - load1, load5, load15 = avg.Load1, avg.Load5, avg.Load15 - } - } - return load1, load5, load15, nil -} - // getLoadFromProc 从 /proc/loadavg 文件中获取负载信息 func getLoadFromProc() (float64, float64, float64, error) { file, err := os.Open("/proc/loadavg") @@ -54,3 +31,30 @@ func getLoadFromProc() (float64, float64, float64, error) { } return 0, 0, 0, nil } + +// 获取系统负载信息 +func getSystemLoad() (float64, float64, float64, error) { + var load1, load5, load15 float64 + var err error + if runtime.GOOS == "linux" { + // 尝试从 /proc/loadavg 文件获取负载信息 + load1, load5, load15, err = getLoadFromProc() + if err != nil { + load1, load5, load15 = 0, 0, 0 + } + } + // 使用 gopsutil 获取负载 + avg, err := load.Avg() + if err != nil { + load1, load5, load15 = 0, 0, 0 + } else { + if avg.Load1 != 0 && avg.Load5 != 0 && avg.Load15 != 0 { + load1, load5, load15 = avg.Load1, avg.Load5, avg.Load15 + } + } + // 有时候获取全为零时尝试使用 wmic 获取负载 + if runtime.GOOS == "windows" && load1 == 0 && load5 == 0 && load15 == 0 { + load1 = utils.GetLoad1() + } + return load1, load5, load15, nil +} diff --git a/system/model/model.go b/system/model/model.go index b2da361..588e813 100644 --- a/system/model/model.go +++ b/system/model/model.go @@ -30,6 +30,7 @@ type SystemInfo struct { Kernel string // 系统内核 Arch string // Uptime string // 正常运行时间 + TimeZone string // 系统时区 VmType string // 虚拟化架构 Load string // load1 load2 load3 NatType string // stun @@ -50,3 +51,7 @@ type Win32_ComputerSystem struct { type Win32_OperatingSystem struct { BuildType string } + +type Win32_TimeZone struct { + Caption string +} diff --git a/system/system.go b/system/system.go index 69b4eb5..9667f04 100644 --- a/system/system.go +++ b/system/system.go @@ -3,6 +3,7 @@ package system import ( "fmt" "github.com/oneclickvirt/basics/system/model" + "github.com/oneclickvirt/basics/system/utils" "strconv" ) @@ -18,7 +19,7 @@ var ( func GetHost() *model.SystemInfo { var ret = &model.SystemInfo{} // 系统信息查询 - cpuType, ret.Uptime, ret.Platform, ret.Kernel, ret.Arch, ret.VmType, ret.NatType, _ = getHostInfo() + cpuType, ret.Uptime, ret.Platform, ret.Kernel, ret.Arch, ret.VmType, ret.NatType, ret.TimeZone, _ = getHostInfo() // CPU信息查询 ret, _ = getCpuInfo(ret, cpuType) // 硬盘信息查询 @@ -34,7 +35,7 @@ func GetHost() *model.SystemInfo { strconv.FormatFloat(load5, 'f', 2, 64) + " / " + strconv.FormatFloat(load15, 'f', 2, 64) // 获取TCP控制算法 - ret.TcpAccelerationMethod = getTCPAccelerateStatus() + ret.TcpAccelerationMethod = utils.GetTCPAccelerateStatus() return ret } @@ -66,6 +67,7 @@ func GetSystemInfo() { fmt.Println("Kernel :", ret.Kernel) } fmt.Println("Uptime :", ret.Uptime) + fmt.Println("Current Time Zone :", ret.TimeZone) fmt.Println("Load :", ret.Load) fmt.Println("VM Type :", ret.VmType) fmt.Println("NAT Type :", ret.NatType) @@ -73,3 +75,8 @@ func GetSystemInfo() { fmt.Println("Tcp Accelerate :", ret.TcpAccelerationMethod) } } + +// TODO +// NAT Type 在 linux 上查不到 +// Boot Path 在 linux 上查询失败 +// Cpu Cache 在 linux 上输出有问题,不能直接转换 string diff --git a/system/tcpcontrol_linux.go b/system/tcpcontrol_linux.go deleted file mode 100644 index 4c2e45d..0000000 --- a/system/tcpcontrol_linux.go +++ /dev/null @@ -1,19 +0,0 @@ -package system - -import ( - "bytes" - "os/exec" -) - -// getTCPAccelerateStatus 查询TCP控制算法 -func getTCPAccelerateStatus() string { - cmd := exec.Command("sysctl", "-n", "net.ipv4.tcp_congestion_control") - var out bytes.Buffer - cmd.Stdout = &out - err := cmd.Run() - if err != nil { - return "" - } else { - return out.String() - } -} diff --git a/system/tcpcontrol_windows.go b/system/tcpcontrol_windows.go deleted file mode 100644 index f7ed9f4..0000000 --- a/system/tcpcontrol_windows.go +++ /dev/null @@ -1,6 +0,0 @@ -package system - -// getTCPAccelerateStatus 查询TCP控制算法 -func getTCPAccelerateStatus() string { - return "" -} diff --git a/system/utils/utils_linux.go b/system/utils/utils_linux.go new file mode 100644 index 0000000..2939c15 --- /dev/null +++ b/system/utils/utils_linux.go @@ -0,0 +1,44 @@ +package utils + +import ( + "bytes" + "os/exec" + "time" +) + +// GetCpuCache 查询CPU三缓 +func GetCpuCache() string { + return "" +} + +func CheckCPUFeatureWindows(subkey string, value string) (string, bool) { + return "", false +} + +func CheckVMTypeWithWIMC() string { + return "" +} + +func GetLoad1() float64 { + return 0 +} + +// GetTCPAccelerateStatus 查询TCP控制算法 +func GetTCPAccelerateStatus() string { + cmd := exec.Command("sysctl", "-n", "net.ipv4.tcp_congestion_control") + var out bytes.Buffer + cmd.Stdout = &out + err := cmd.Run() + if err != nil { + return "" + } else { + return out.String() + } +} + +// GetTimeZone 获取当前时区 +func GetTimeZone() string { + local := time.Now().Location() + CurrentTimeZone := local.String() + return CurrentTimeZone +} diff --git a/system/utils/utils_windows.go b/system/utils/utils_windows.go new file mode 100644 index 0000000..145ecab --- /dev/null +++ b/system/utils/utils_windows.go @@ -0,0 +1,132 @@ +package utils + +import ( + "fmt" + "math" + "strings" + + "github.com/oneclickvirt/basics/system/model" + "github.com/yusufpapurcu/wmi" + "golang.org/x/sys/windows/registry" +) + +// GetCpuCache 查询CPU三缓 +func GetCpuCache() string { + var processors []model.Win32_Processor + err := wmi.Query("SELECT L2CacheSize, L3CacheSize FROM Win32_Processor", &processors) + if err == nil { + if len(processors) > 0 { + L1CacheSizeStr := "null" + L2CacheSize := processors[0].L2CacheSize + L3CacheSize := processors[0].L3CacheSize + var L2CacheSizeStr, L3CacheSizeStr string + if L2CacheSize >= 1024*1024 { + L2CacheSizeStr = fmt.Sprintf("%.2f GB", float64(L2CacheSize)/(1024*1024)) + } else if L2CacheSize >= 1024 { + L2CacheSizeStr = fmt.Sprintf("%.2f MB", float64(L2CacheSize)/1024) + } else { + L2CacheSizeStr = fmt.Sprintf("%d KB", L2CacheSize) + } + if L3CacheSize >= 1024*1024 { + L3CacheSizeStr = fmt.Sprintf("%.2f GB", float64(L3CacheSize)/(1024*1024)) + } else if L3CacheSize >= 1024 { + L3CacheSizeStr = fmt.Sprintf("%.2f MB", float64(L3CacheSize)/1024) + } else { + L3CacheSizeStr = fmt.Sprintf("%d KB", L3CacheSize) + } + return fmt.Sprintf("L1: %s / L2: %s / L3: %s", L1CacheSizeStr, L2CacheSizeStr, L3CacheSizeStr) + } else { + return "" + } + } else { + return "" + } +} + +func CheckCPUFeatureWindows(subkey string, value string) (string, bool) { + k, err := registry.OpenKey(registry.LOCAL_MACHINE, subkey, registry.READ) + if err != nil { + return "❌ Disabled", false + } + defer k.Close() + val, _, err := k.GetStringValue(value) + if err != nil { + return "❌ Disabled", false + } + if strings.Contains(val, "1") { + return "✔️ Enabled", true + } + return "❌ Disabled", false +} + +func CheckVMTypeWithWIMC() string { + var ( + computers []model.Win32_ComputerSystem + operatingSystems []model.Win32_OperatingSystem + VmType string + ) + err1 := wmi.Query("SELECT * FROM Win32_ComputerSystem", &computers) + err2 := wmi.Query("SELECT * FROM Win32_OperatingSystem", &operatingSystems) + if err1 == nil || err2 == nil { + if len(computers) > 0 || len(operatingSystems) > 0 { + switch { + case (len(computers) > 0 && strings.Contains(computers[0].SystemType, "Multiprocessor Free")) || + (len(operatingSystems) > 0 && strings.Contains(operatingSystems[0].BuildType, "Multiprocessor Free")): + VmType = "Physical-Machine" + "(" + "Multiprocessor Free" + ")" + case (len(computers) > 0 && strings.Contains(computers[0].SystemType, "Virtual Machine")) || + (len(operatingSystems) > 0 && strings.Contains(operatingSystems[0].BuildType, "Virtual Machine")): + VmType = "Hyper-V" + "(" + "Virtual Machine" + ")" + case (len(computers) > 0 && strings.Contains(computers[0].SystemType, "VMware")) || + (len(operatingSystems) > 0 && strings.Contains(operatingSystems[0].BuildType, "VMware")): + VmType = "VMware" + default: + if len(computers) > 0 && len(operatingSystems) > 0 { + VmType = computers[0].SystemType + "(" + operatingSystems[0].BuildType + ")" + } else if len(computers) > 0 { + VmType = computers[0].SystemType + } else if len(operatingSystems) > 0 { + VmType = operatingSystems[0].BuildType + } + } + } + } + return VmType +} + +func GetLoad1() float64 { + var load1 float64 + type Win32_Processor struct { + LoadPercentage uint16 + NumberOfCores uint32 + } + var processors []Win32_Processor + query := "SELECT LoadPercentage, NumberOfCores FROM Win32_Processor" + err := wmi.Query(query, &processors) + if err == nil { + for _, processor := range processors { + tempLoad := float64(processor.LoadPercentage) / float64(processor.NumberOfCores) + load1 = math.Round(tempLoad*100) / 100 + } + } + return load1 +} + +// GetTCPAccelerateStatus 查询TCP控制算法 +func GetTCPAccelerateStatus() string { + return "" +} + +// GetTimeZone 获取当前时区 +func GetTimeZone() string { + var timezone []model.Win32_TimeZone + err := wmi.Query("SELECT * FROM Win32_TimeZone", &timezone) + if err == nil { + if len(timezone) > 0 { + return timezone[0].Caption + } else { + return "" + } + } else { + return "" + } +}