refactor(edge): 抽取边缘运行时共享包并完成 Phase 3 重构

- 新增 internal/apps/edge/,三组件改为薄包装,删除 3000+ 行重复代码
- Agent 心跳周期下沉至 heartbeat/cycle.go
- 协议类型迁入 pkg/protocol/agent.go
- 补充设计文档与 changelog
This commit is contained in:
ryan
2026-06-19 14:56:00 +08:00
parent cc5e53c51e
commit db9a9f98fd
53 changed files with 2091 additions and 2947 deletions
+4 -87
View File
@@ -1,49 +1,18 @@
package config
import (
"context"
"encoding/json"
"errors"
"net"
"os"
"path/filepath"
"strings"
"time"
"github.com/Rain-kl/Wavelet/pkg/geoip"
"github.com/Rain-kl/Wavelet/pkg/geoip/iputil"
edgeconfig "github.com/Rain-kl/Wavelet/internal/apps/edge/config"
"github.com/Rain-kl/Wavelet/internal/apps/edge/nodeip"
)
type MillisecondDuration time.Duration
func (d *MillisecondDuration) UnmarshalJSON(b []byte) error {
var v interface{}
if err := json.Unmarshal(b, &v); err != nil {
return err
}
switch value := v.(type) {
case float64:
*d = MillisecondDuration(time.Duration(value) * time.Millisecond)
return nil
case string:
duration, err := time.ParseDuration(value)
if err != nil {
return err
}
*d = MillisecondDuration(duration)
return nil
default:
return errors.New("invalid duration format")
}
}
func (d MillisecondDuration) Duration() time.Duration {
return time.Duration(d)
}
func (d MillisecondDuration) String() string {
return time.Duration(d).String()
}
type MillisecondDuration = edgeconfig.MillisecondDuration
type Config struct {
ServerURL string `json:"server_url"`
@@ -130,7 +99,7 @@ func applyDefaults(cfg *Config, baseDir string) {
cfg.NodeName = strings.TrimSpace(host)
}
if cfg.NodeIP == "" {
cfg.NodeIP = detectNodeIP()
cfg.NodeIP = nodeip.Detect()
}
if cfg.StatePath == "" {
cfg.StatePath = filepath.Join(cfg.DataDir, "relay-state.json")
@@ -180,56 +149,4 @@ func (cfg *Config) Save() error {
return os.WriteFile(cfg.configPath, data, 0o644)
}
func detectNodeIP() string {
if ip := detectOutboundNodeIP(); ip != "" {
return ip
}
return detectLocalNodeIP()
}
func detectOutboundNodeIP() string {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
ip, err := geoip.GetOutboundIP(ctx)
if err != nil || ip == nil {
return ""
}
return ip.String()
}
func detectLocalNodeIP() string {
interfaces, err := net.Interfaces()
if err != nil {
return ""
}
bestIP := ""
bestPriority := -1
for _, iface := range interfaces {
if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 {
continue
}
addrs, err := iface.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
ipNet, ok := addr.(*net.IPNet)
if !ok || ipNet.IP == nil || ipNet.IP.IsLoopback() {
continue
}
ipv4 := ipNet.IP.To4()
if ipv4 == nil {
continue
}
priority := iputil.Score(ipv4)
if priority > bestPriority {
bestIP = ipv4.String()
bestPriority = priority
}
if bestPriority == 2 {
return bestIP
}
}
}
return bestIP
}