407 lines
11 KiB
Go
407 lines
11 KiB
Go
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"`
|
||
}
|