Files
Meshray-Manager/internal/ctr/ctr.go
T
2026-06-30 15:14:37 +08:00

407 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package ctr
import (
"fmt"
"strconv"
"sync"
"git.zkcoi.com/zkcoi/meshray/core"
"git.zkcoi.com/zkcoi/meshray/core/connect"
"go.uber.org/zap"
)
// Ctr meshray-ctr 调度中心
type Ctr struct {
name string // 组网名称(用于日志)
networkID uint64 // 组网 ID(雪花算法 ID
config *CtrConfig
logger *zap.Logger
// WireGuard 管理器
wgManager *WGManager
// Core 实例(直接集成,无需 gRPC)
coreInst *core.Core
mu sync.RWMutex
}
// CtrConfig 配置
type CtrConfig struct {
// 空配置,保留结构体以备未来扩展
}
// NewCtr 创建调度中心
func NewCtr(name string, networkID uint64, config *CtrConfig, logger *zap.Logger) (*Ctr, error) {
ctr := &Ctr{
name: name,
networkID: networkID,
config: config,
logger: logger,
}
// 初始化 WireGuard 管理器
ctr.wgManager = NewWGManager(logger)
// 初始化 Core 实例(直接集成,无需 gRPC)
ctr.coreInst = core.NewCore(logger)
return ctr, nil
}
// Start 启动调度中心
func (c *Ctr) Start() error {
c.mu.Lock()
defer c.mu.Unlock()
c.logger.Info("启动 meshray-ctr",
zap.String("name", c.name),
zap.Uint64("network_id", c.networkID))
// ✅ Watchdog 监控暂不实现(P3 阶段)
// go c.watchdog.Start()
return nil
}
// Stop 停止调度中心
func (c *Ctr) Stop() error {
c.mu.Lock()
defer c.mu.Unlock()
c.logger.Info("停止 meshray-ctr",
zap.Uint64("network_id", c.networkID))
// 停止 Core 实例(直接调用方法)
if c.coreInst != nil {
// ✅ Close 方法已实现(会停止所有 Engine)
c.coreInst.Close()
}
// 停止 WireGuard 管理
if err := c.wgManager.Stop(); err != nil {
c.logger.Error("停止 WireGuard 管理失败", zap.Error(err))
}
return nil
}
// CreateNetwork 创建网络(根据组网模式决定行为)
// - 原生模式:仅创建 WG 设备
// - 增强模式:创建 WG 设备 + 启动 Core 实例
func (c *Ctr) CreateNetwork(networkID uint64, subnet string, listenPort int, meshMode string) error {
c.mu.Lock()
defer c.mu.Unlock()
c.logger.Info("开始创建网络",
zap.Uint64("network_id", networkID),
zap.String("subnet", subnet),
zap.Int("listen_port", listenPort),
zap.String("mesh_mode", meshMode))
// 1. 创建 WireGuard 设备(两种模式都需要)
networkIDStr := strconv.FormatUint(networkID, 10)
if err := c.wgManager.CreateDevice(networkIDStr, subnet, listenPort); err != nil {
return fmt.Errorf("创建 WireGuard 设备失败:%w", err)
}
c.logger.Debug("WireGuard 设备创建成功",
zap.Uint64("network_id", networkID))
// 2. 仅增强模式需要创建并启动 Core 实例
if meshMode == "enhanced" {
// 直接调用 Core 实例的方法(无需 gRPC)
metrics := core.NewMetrics()
engine, err := c.coreInst.CreateEngine(networkIDStr, metrics)
if err != nil {
c.wgManager.DeleteDevice(networkIDStr) // 回滚 WG设备
c.logger.Error("创建 Engine 失败",
zap.Uint64("network_id", networkID),
zap.Error(err))
return fmt.Errorf("创建 Engine 失败:%w", err)
}
if err := engine.Start(); err != nil {
// ✅ 调用 Stop 方法停止(会清理所有资源)
engine.Stop()
c.wgManager.DeleteDevice(networkIDStr) // 回滚 WG 设备
c.logger.Error("启动 Engine 失败",
zap.Uint64("network_id", networkID),
zap.Error(err))
return fmt.Errorf("启动 Engine 失败:%w", err)
}
c.logger.Info("增强模式:Engine 实例已启动",
zap.Uint64("network_id", networkID))
} else {
c.logger.Info("原生模式:仅创建 WG 设备,不启动 Core",
zap.Uint64("network_id", networkID))
}
c.logger.Info("网络创建成功",
zap.Uint64("network_id", networkID),
zap.String("mesh_mode", meshMode))
return nil
}
// DeleteNetwork 删除网络
func (c *Ctr) DeleteNetwork(networkID uint64) error {
c.mu.Lock()
defer c.mu.Unlock()
c.logger.Info("开始删除网络",
zap.Uint64("network_id", networkID))
// 1. Core 实例不需要显式删除(它是内存中的对象)
// 如果需要清理,可以在未来实现 Engine.Stop() 方法
networkIDStr := strconv.FormatUint(networkID, 10)
// 2. 删除 WireGuard 设备
if err := c.wgManager.DeleteDevice(networkIDStr); err != nil {
return fmt.Errorf("删除 WireGuard 设备失败:%w", err)
}
c.logger.Info("网络删除成功",
zap.Uint64("network_id", networkID))
return nil
}
// AddPeer 添加 Peer
func (c *Ctr) AddPeer(networkID uint64, publicKey, allowedIP string) error {
c.mu.RLock()
defer c.mu.RUnlock()
c.logger.Info("添加 Peer",
zap.Uint64("network_id", networkID),
zap.String("public_key", publicKey[:8]+"..."))
// 1. 添加到 WireGuard
networkIDStr := strconv.FormatUint(networkID, 10)
if err := c.wgManager.AddPeer(networkIDStr, publicKey, allowedIP); err != nil {
return fmt.Errorf("添加 Peer 失败:%w", err)
}
// 2. 通知 Core
// 如果已经在 Enhanced 模式,需要接管刚刚加入的这个 Peer
engine, err := c.coreInst.GetEngine(networkIDStr)
if err == nil && engine != nil {
// 引擎存在,说明是 enhanced 模式
// 由 Core 分配一个本地端口
localPort, err := engine.Bind(publicKey, 0)
if err != nil {
c.logger.Error("增强模式动态 AddPeer Bind 失败", zap.Error(err))
} else {
// 通知 WG 更新为本地代理 Endpoint
newEndpoint := fmt.Sprintf("127.0.0.1:%d", localPort)
if err := c.wgManager.UpdatePeerEndpoint(networkIDStr, publicKey, newEndpoint); err != nil {
c.logger.Warn("增强模式自动重写 Endpoint 失败", zap.Error(err))
engine.Unbind(publicKey)
} else {
c.logger.Info("增强模式:动态 Peer 添加并成功代理给 Core",
zap.String("public_key", publicKey[:8]+"..."),
zap.String("new_endpoint", newEndpoint))
}
}
} else {
c.logger.Debug("Core 未启动,普通模式无需代理 Peer", zap.Uint64("network_id", networkID))
}
return nil
}
// RemovePeer 移除 Peer
func (c *Ctr) RemovePeer(networkID uint64, publicKey string) error {
c.mu.RLock()
defer c.mu.RUnlock()
c.logger.Info("移除 Peer",
zap.Uint64("network_id", networkID),
zap.String("public_key", publicKey[:8]+"..."))
// 从 WireGuard 移除
networkIDStr := strconv.FormatUint(networkID, 10)
if err := c.wgManager.RemovePeer(networkIDStr, publicKey); err != nil {
return fmt.Errorf("移除 Peer 失败:%w", err)
}
// 通知 Core 卸载这台 Peer 的监听
engine, err := c.coreInst.GetEngine(networkIDStr)
if err == nil && engine != nil {
engine.Unbind(publicKey)
c.logger.Info("增强模式:Core 已解除对该 Peer 的挂载", zap.String("public_key", publicKey[:8]+"..."))
}
return nil
}
// SetSTUNTURNConfig 为指定网络设置 STUN/TURN 配置
func (c *Ctr) SetSTUNTURNConfig(networkID uint64, stunServers []string, turnServers []connect.TURNServerConfig) error {
c.mu.RLock()
defer c.mu.RUnlock()
networkIDStr := strconv.FormatUint(networkID, 10)
// 获取 Engine 实例
engine, err := c.coreInst.GetEngine(networkIDStr)
if err != nil {
c.logger.Debug("网络未启动增强模式,跳过 STUN/TURN 配置",
zap.Uint64("network_id", networkID))
return nil // 无需错误,因为原生模式不需要
}
// 更新 WebRTC 工厂的 ICE 配置
engine.SetICEConfig(connect.ICEConfig{
STUNServers: stunServers,
TURNServers: turnServers,
})
c.logger.Info("STUN/TURN 配置已设置",
zap.Uint64("network_id", networkID),
zap.Int("stun_count", len(stunServers)),
zap.Int("turn_count", len(turnServers)))
return nil
}
func (c *Ctr) GetStatus(networkID uint64) (*NetworkStatus, error) {
c.mu.RLock()
defer c.mu.RUnlock()
networkIDStr := strconv.FormatUint(networkID, 10)
status := &NetworkStatus{
NetworkID: networkIDStr,
}
// 获取 WireGuard 状态
wgStatus, err := c.wgManager.GetStatus(networkIDStr)
if err != nil {
return nil, err
}
status.WGStatus = wgStatus
// 获取 Core 状态(直接调用 Engine 的方法)
engine, err := c.coreInst.GetEngine(networkIDStr)
if err == nil && engine != nil {
coreStatus, err := engine.GetStatus()
if err == nil {
status.CoreStatus = coreStatus
}
}
return status, nil
}
// SwitchMode 切换传输模式(原生→增强)
// 仅支持 "native" → "enhanced" 单向切换
func (c *Ctr) SwitchMode(networkID uint64, mode string) error {
c.mu.Lock()
defer c.mu.Unlock()
c.logger.Info("开始切换传输模式",
zap.Uint64("network_id", networkID),
zap.String("target_mode", mode))
// 1. 验证目标模式
if mode != "enhanced" {
return fmt.Errorf("仅支持切换到 enhanced 模式,当前请求:%s", mode)
}
networkIDStr := strconv.FormatUint(networkID, 10)
// 2. 获取当前 WG 状态(获取 Peer 数量)
wgStatus, err := c.wgManager.GetStatus(networkIDStr)
if err != nil {
return fmt.Errorf("获取 WG 状态失败:%w", err)
}
c.logger.Info("获取到 WG 状态",
zap.Int("peer_count", wgStatus.PeerCount))
// 3. 创建并启动 Core Engine(增强模式核心)
metrics := core.NewMetrics()
engine, err := c.coreInst.CreateEngine(networkIDStr, metrics)
if err != nil {
return fmt.Errorf("创建 Core Engine 失败:%w", err)
}
if err := engine.Start(); err != nil {
return fmt.Errorf("启动 Core Engine 失败:%w", err)
}
c.logger.Info("Core Engine 已启动",
zap.Uint64("network_id", networkID))
// 4. 获取 Peer 列表
peers, err := c.wgManager.ListPeers(networkIDStr)
if err != nil {
return fmt.Errorf("获取 Peer 列表失败:%w", err)
}
// 5. 修改 Peer Endpoint → 127.0.0.1:{port},并且让 Core 绑定
// 增强模式下,所有 Peer 的 Endpoint 都指向本地回环地址
for _, peer := range peers {
// 1. Core 引擎动态接管,传 0 意为让操作系统挑个未占用的随意回环端口
localPort, err := engine.Bind(peer.PublicKey, 0)
if err != nil {
c.logger.Error("Engine Bind 失败",
zap.String("public_key", peer.PublicKey[:8]+"..."),
zap.Error(err))
continue
}
newEndpoint := fmt.Sprintf("127.0.0.1:%d", localPort)
// 2. 将此端口告知 WG 更新 Endpoint
if err := c.wgManager.UpdatePeerEndpoint(networkIDStr, peer.PublicKey, newEndpoint); err != nil {
c.logger.Warn("更新 Peer Endpoint 失败",
zap.String("public_key", peer.PublicKey[:8]+"..."),
zap.Error(err))
// 如果更新失败,解绑 Core
engine.Unbind(peer.PublicKey)
continue
}
c.logger.Info("Peer Endpoint 已成功切换并接入 Core",
zap.String("public_key", peer.PublicKey[:8]+"..."),
zap.String("original_endpoint", peer.Endpoint),
zap.String("new_endpoint", newEndpoint))
}
c.logger.Info("传输模式切换成功(基础功能已实现,P3 阶段待完善)",
zap.Uint64("network_id", networkID),
zap.String("mode", mode))
return nil
}
// UpdateCoreConfig 更新 Core 配置(策略修改后同步)
// ✅ P3-1 阶段实现
func (c *Ctr) UpdateCoreConfig(networkID uint64, config interface{}) error {
c.mu.RLock()
defer c.mu.RUnlock()
c.logger.Info("更新 Core 配置",
zap.Uint64("network_id", networkID))
// ✅ P3-1 阶段 - 暂不实现
// 未来实现:
// 1. 根据策略类型解析配置
// 2. 调用 Core 的 UpdateConfig 方法
// 3. 持久化到数据库
return fmt.Errorf("UpdateCoreConfig 尚未实现(P3-1 阶段)")
}
// GetWGMode 获取系统 WG 模式
func (c *Ctr) GetWGMode() string {
return c.wgManager.GetWGMode()
}
// NetworkStatus 网络状态
type NetworkStatus struct {
NetworkID string `json:"network_id"`
WGStatus *WGStatus `json:"wg_status"`
CoreStatus *core.EngineStatus `json:"core_status,omitempty"`
}