79 lines
1.7 KiB
Go
79 lines
1.7 KiB
Go
package core
|
|
|
|
import (
|
|
"net"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// PingResult contains the result of a ping to a server.
|
|
type PingResult struct {
|
|
Ms int64 // round-trip time in ms, -1 if failed
|
|
Color string
|
|
}
|
|
|
|
// PingAddress pings a single address using TCP connect (ICMP requires elevated privileges).
|
|
// Returns round-trip time in ms or -1 on failure.
|
|
func PingAddress(address string, timeout time.Duration) int64 {
|
|
if timeout == 0 {
|
|
timeout = 3 * time.Second
|
|
}
|
|
|
|
start := time.Now()
|
|
conn, err := net.DialTimeout("tcp", address+":443", timeout)
|
|
if err != nil {
|
|
return -1
|
|
}
|
|
conn.Close()
|
|
return time.Since(start).Milliseconds()
|
|
}
|
|
|
|
// PingConfig pings a VPN config and returns the result.
|
|
func PingConfig(config *VpnConfig) PingResult {
|
|
link := TryParseLink(config.Link)
|
|
if link == nil {
|
|
return PingResult{Ms: -1, Color: "#666"}
|
|
}
|
|
|
|
ms := PingAddress(link.Address, 3*time.Second)
|
|
if ms < 0 {
|
|
return PingResult{Ms: -1, Color: "#666"}
|
|
}
|
|
return PingResult{Ms: ms, Color: GetPingColor(ms)}
|
|
}
|
|
|
|
// PingAllConfigs pings all configs concurrently.
|
|
func PingAllConfigs(configs []VpnConfig) []PingResult {
|
|
results := make([]PingResult, len(configs))
|
|
var wg sync.WaitGroup
|
|
|
|
for i := range configs {
|
|
wg.Add(1)
|
|
go func(idx int) {
|
|
defer wg.Done()
|
|
results[idx] = PingConfig(&configs[idx])
|
|
}(i)
|
|
}
|
|
|
|
wg.Wait()
|
|
return results
|
|
}
|
|
|
|
// GetPingColor returns a color hex code based on ping latency.
|
|
func GetPingColor(ms int64) string {
|
|
switch {
|
|
case ms < 50:
|
|
return "#4CAF50" // green
|
|
case ms < 100:
|
|
return "#8BC34A" // light green
|
|
case ms < 150:
|
|
return "#CDDC39" // lime
|
|
case ms < 200:
|
|
return "#FFC107" // amber
|
|
case ms < 300:
|
|
return "#FF9800" // orange
|
|
default:
|
|
return "#E53935" // red
|
|
}
|
|
}
|