Files
waf-platform/EdgeHttpDNS/internal/nodes/status_manager.go
2026-02-27 10:35:22 +08:00

145 lines
3.2 KiB
Go

package nodes
import (
"encoding/json"
"log"
"os"
"runtime"
"strconv"
"strings"
"time"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeHttpDNS/internal/configs"
teaconst "github.com/TeaOSLab/EdgeHttpDNS/internal/const"
"github.com/TeaOSLab/EdgeHttpDNS/internal/rpc"
"github.com/TeaOSLab/EdgeHttpDNS/internal/utils"
)
type StatusManager struct {
quitCh <-chan struct{}
ticker *time.Ticker
}
func NewStatusManager(quitCh <-chan struct{}) *StatusManager {
return &StatusManager{
quitCh: quitCh,
ticker: time.NewTicker(30 * time.Second),
}
}
func (m *StatusManager) Start() {
defer m.ticker.Stop()
m.update()
for {
select {
case <-m.ticker.C:
m.update()
case <-m.quitCh:
return
}
}
}
func (m *StatusManager) update() {
status := m.collectStatus()
statusJSON, err := json.Marshal(status)
if err != nil {
log.Println("[HTTPDNS_NODE][status]marshal status failed:", err.Error())
return
}
rpcClient, err := rpc.SharedRPC()
if err != nil {
log.Println("[HTTPDNS_NODE][status]rpc unavailable:", err.Error())
return
}
config, err := configs.SharedAPIConfig()
if err != nil {
log.Println("[HTTPDNS_NODE][status]load config failed:", err.Error())
return
}
nodeId, _ := strconv.ParseInt(config.NodeId, 10, 64)
_, err = rpcClient.HTTPDNSNodeRPC.UpdateHTTPDNSNodeStatus(rpcClient.Context(), &pb.UpdateHTTPDNSNodeStatusRequest{
NodeId: nodeId,
IsUp: true,
IsInstalled: true,
IsActive: true,
StatusJSON: statusJSON,
})
if err != nil {
log.Println("[HTTPDNS_NODE][status]update status failed:", err.Error())
}
}
func (m *StatusManager) collectStatus() *nodeconfigs.NodeStatus {
now := time.Now().Unix()
status := &nodeconfigs.NodeStatus{
BuildVersion: teaconst.Version,
BuildVersionCode: utils.VersionToLong(teaconst.Version),
ConfigVersion: 0,
OS: runtime.GOOS,
Arch: runtime.GOARCH,
CPULogicalCount: runtime.NumCPU(),
CPUPhysicalCount: runtime.NumCPU(),
IsActive: true,
ConnectionCount: 0,
UpdatedAt: now,
Timestamp: now,
}
rpcClient, err := rpc.SharedRPC()
if err == nil {
total, failed, avgCostSeconds := rpcClient.GetAndResetMetrics()
if total > 0 {
status.APISuccessPercent = float64(total-failed) * 100.0 / float64(total)
status.APIAvgCostSeconds = avgCostSeconds
}
}
hostname, _ := os.Hostname()
status.Hostname = hostname
exePath, _ := os.Executable()
status.ExePath = exePath
var memStats runtime.MemStats
runtime.ReadMemStats(&memStats)
status.MemoryTotal = memStats.Sys
if status.MemoryTotal > 0 {
status.MemoryUsage = float64(memStats.Alloc) / float64(status.MemoryTotal)
}
load1m, load5m, load15m := readLoadAvg()
status.Load1m = load1m
status.Load5m = load5m
status.Load15m = load15m
return status
}
func readLoadAvg() (float64, float64, float64) {
data, err := os.ReadFile("/proc/loadavg")
if err != nil {
return 0, 0, 0
}
parts := strings.Fields(strings.TrimSpace(string(data)))
if len(parts) < 3 {
return 0, 0, 0
}
load1m, _ := strconv.ParseFloat(parts[0], 64)
load5m, _ := strconv.ParseFloat(parts[1], 64)
load15m, _ := strconv.ParseFloat(parts[2], 64)
return load1m, load5m, load15m
}