3x-ui/util/sys/sys_windows.go
2025-09-16 14:15:18 +02:00

111 lines
2.2 KiB
Go

//go:build windows
// +build windows
package sys
import (
"errors"
"sync"
"syscall"
"unsafe"
"github.com/shirou/gopsutil/v4/net"
)
func GetConnectionCount(proto string) (int, error) {
if proto != "tcp" && proto != "udp" {
return 0, errors.New("invalid protocol")
}
stats, err := net.Connections(proto)
if err != nil {
return 0, err
}
return len(stats), nil
}
func GetTCPCount() (int, error) {
return GetConnectionCount("tcp")
}
func GetUDPCount() (int, error) {
return GetConnectionCount("udp")
}
// --- CPU Utilization (Windows native) ---
var (
modKernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetSystemTimes = modKernel32.NewProc("GetSystemTimes")
cpuMu sync.Mutex
lastIdle uint64
lastKernel uint64
lastUser uint64
hasLast bool
)
type filetime struct {
LowDateTime uint32
HighDateTime uint32
}
func ftToUint64(ft filetime) uint64 {
return (uint64(ft.HighDateTime) << 32) | uint64(ft.LowDateTime)
}
// CPUPercentRaw returns the instantaneous total CPU utilization percentage using
// Windows GetSystemTimes across all logical processors. The first call returns 0
// as it initializes the baseline. Subsequent calls compute deltas.
func CPUPercentRaw() (float64, error) {
var idleFT, kernelFT, userFT filetime
r1, _, e1 := procGetSystemTimes.Call(
uintptr(unsafe.Pointer(&idleFT)),
uintptr(unsafe.Pointer(&kernelFT)),
uintptr(unsafe.Pointer(&userFT)),
)
if r1 == 0 { // failure
if e1 != nil {
return 0, e1
}
return 0, syscall.GetLastError()
}
idle := ftToUint64(idleFT)
kernel := ftToUint64(kernelFT)
user := ftToUint64(userFT)
cpuMu.Lock()
defer cpuMu.Unlock()
if !hasLast {
lastIdle = idle
lastKernel = kernel
lastUser = user
hasLast = true
return 0, nil
}
idleDelta := idle - lastIdle
kernelDelta := kernel - lastKernel
userDelta := user - lastUser
// Update for next call
lastIdle = idle
lastKernel = kernel
lastUser = user
total := kernelDelta + userDelta
if total == 0 {
return 0, nil
}
// On Windows, kernel time includes idle time; busy = total - idle
busy := total - idleDelta
pct := float64(busy) / float64(total) * 100.0
// lower bound not needed; ratios of uint64 are non-negative
if pct > 100 {
pct = 100
}
return pct, nil
}