feat: fix dashboard real-time data sync, stabilize node order and eliminate UI jitter
Release / Build & Release (push) Canceled after 0s

This commit is contained in:
kory
2026-09-30 13:17:19 +08:00
parent bd44465eaa
commit af63e3a120
20 changed files with 2133 additions and 90 deletions
+115
View File
@@ -0,0 +1,115 @@
package cluster
import (
"encoding/json"
"net"
"net/http"
"strings"
"sync"
"time"
)
type GeoLocation struct {
CountryCode string `json:"countryCode"`
Country string `json:"country"`
Status string `json:"status"`
}
var (
geoCache sync.Map
client = &http.Client{Timeout: 4 * time.Second}
)
func isPrivateIP(ipStr string) bool {
ip := net.ParseIP(ipStr)
if ip == nil {
return false
}
if ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() {
return true
}
return false
}
// ExtractIPFromRequest retrieves the real client IP from HTTP headers or RemoteAddr
func ExtractIPFromRequest(r *http.Request) string {
if fwd := r.Header.Get("X-Forwarded-For"); fwd != "" {
parts := strings.Split(fwd, ",")
for _, p := range parts {
clean := strings.TrimSpace(p)
if clean != "" && !isPrivateIP(clean) {
return clean
}
}
if len(parts) > 0 {
clean := strings.TrimSpace(parts[0])
if clean != "" {
return clean
}
}
}
if realIP := strings.TrimSpace(r.Header.Get("X-Real-IP")); realIP != "" {
return realIP
}
host, _, err := net.SplitHostPort(r.RemoteAddr)
if err == nil {
return host
}
return r.RemoteAddr
}
// ResolveIP returns countryCode (e.g. "HK", "SG") and countryName (e.g. "Hong Kong", "Singapore")
func ResolveIP(ipStr string) (string, string) {
ipStr = strings.TrimSpace(ipStr)
if ipStr == "" {
return "", ""
}
if isPrivateIP(ipStr) {
return "CN", "中国"
}
if v, ok := geoCache.Load(ipStr); ok {
if g, ok := v.(GeoLocation); ok {
return g.CountryCode, g.Country
}
}
url := "http://ip-api.com/json/" + ipStr + "?fields=status,country,countryCode"
resp, err := client.Get(url)
if err != nil {
return "", ""
}
defer resp.Body.Close()
var g GeoLocation
if err := json.NewDecoder(resp.Body).Decode(&g); err != nil {
return "", ""
}
if g.Status == "success" && g.CountryCode != "" {
geoCache.Store(ipStr, g)
return g.CountryCode, g.Country
}
return "", ""
}
// ResolveLocalPublicIP queries the hub host's public IP location
func ResolveLocalPublicIP() (string, string) {
if v, ok := geoCache.Load("__local__"); ok {
if g, ok := v.(GeoLocation); ok {
return g.CountryCode, g.Country
}
}
resp, err := client.Get("http://ip-api.com/json/?fields=status,country,countryCode")
if err != nil {
return "HK", "中国香港"
}
defer resp.Body.Close()
var g GeoLocation
if err := json.NewDecoder(resp.Body).Decode(&g); err != nil {
return "HK", "中国香港"
}
if g.Status == "success" && g.CountryCode != "" {
geoCache.Store("__local__", g)
return g.CountryCode, g.Country
}
return "HK", "中国香港"
}