Files
Meshray-Manager/docs/Service 层架构详解.md
2026-06-30 15:14:37 +08:00

19 KiB
Raw Permalink Blame History

MeshRay Service 层架构详解

文档版本: v1.0
更新时间: 2026-03-24
适用范围: internal/service/ 模块


📊 Service 层在整体架构中的位置

┌─────────────────────────────────────────────┐
│         Web UIVue 3 + Element Plus        │
└────────────────┬────────────────────────────┘
                 │ REST API / WebSocket
┌────────────────▼────────────────────────────┐
│      API HandlerGin 接入层)               │
│  - network_handler.go                       │
│  - device_handler.go                        │
│  - user_handler.go                          │
│  - service_handler.go                       │
└────────────────┬────────────────────────────┘
                 │ 函数调用
┌────────────────▼────────────────────────────┐
│     Service Layer(业务逻辑层)⭐核心        │
│  - NetworkService    ← 组网管理             │
│  - DeviceService     ← 设备管理             │
│  - PolicyService     ← 策略管理             │
│  - ExternalService   ← 外部服务管理         │
│  - UserService       ← 用户认证             │
│  - MonitorService    ← 监控告警             │
│  - DDNSService       ← DDNS 同步             │
│  - AuditService      ← 审计日志             │
└──────┬──────────────────────────────────────┘
       │
       ├──────────────────────────────────────┐
       │                                      │
┌──────▼──────┐                      ┌────────▼────────┐
│ Store Layer │                      │  Ctr Layer      │
│ (数据持久化) │                      │  (实时控制)     │
│             │                      │                 │
│ - networks  │                      │ - wgctrl        │
│ - devices   │                      │ - core gRPC     │
│ - policies  │                      │ - 实时调度      │
│ - users     │                      │                 │
│ - services  │                      │                 │
└─────────────┘                      └─────────────────┘

关键点

  • Service 层是业务逻辑的核心
  • Ctr 层只是 Service 层调用的一个执行器
  • 很多 Service 功能完全不依赖 Ctr(如用户登录、策略校验)

🎯 Service 层模块划分

完整的服务模块清单

internal/service/
├── service.go                  # Service 层总入口和依赖注入
│   type ServiceProvider struct {
│       network    *NetworkService
│       device     *DeviceService
│       policy     *PolicyService
│       external   *ExternalService
│       user       *UserService
│       monitor    *MonitorService
│       ddns       *DDNSService
│       audit      *AuditService
│   }
│
├── network.go                  # 组网管理服务
│   ├── ListNetworks()          []Network           # 获取网络列表
│   ├── CreateNetwork()         (*Network, error)   # 创建网络
│   ├── DeleteNetwork()         error               # 删除网络
│   ├── UpdateNetwork()         error               # 更新网络配置
│   ├── GenerateMeshSeed()      (*MeshSeed, error)  # 生成 MeshSeed
│   ├── ParseMeshSeed()         (*MeshSeed, error)  # 解析 MeshSeed
│   └── JoinNetwork()           error               # 加入网络
│
├── device.go                   # 设备管理服务
│   ├── ListDevices()           []Device            # 设备列表
│   ├── AddDevice()             (*Device, error)    # 添加设备
│   ├── RemoveDevice()          error               # 删除设备
│   ├── RegenerateKey()         error               # 重新生成密钥
│   ├── GetDeviceConfig()       (*WGConfig, error)  # 获取 WG 配置
│   └── ImportDevice()          error               # 导入现有设备
│
├── policy.go                   # 策略管理服务
│   ├── ListPolicies()          []Policy            # 策略列表
│   ├── SetPolicy()             error               # 设置传输策略
│   ├── GetPolicy()             (*Policy, error)    # 获取策略
│   ├── ValidatePolicy()        error               # 验证策略合法性
│   ├── GetEffectivePolicy()    (*Policy, error)    # 获取生效策略
│   └── ResetPolicy()           error               # 重置策略
│
├── external_service.go         # 外部服务管理服务
│   ├── ListServices()          []ExternalService   # 服务列表
│   ├── AddService()            error               # 添加服务
│   ├── UpdateService()         error               # 更新服务
│   ├── DeleteService()         error               # 删除服务
│   ├── TestConnectivity()      error               # 测试连通性
│   ├── GetServiceSchema()      (string, error)     # 获取 JSON Schema
│   └── ListByCategory()        []ExternalService   # 按分类筛选
│
├── user.go                     # 用户认证服务
│   ├── Login()                 (string, error)     # 登录 → JWT Token
│   ├── Register()              error               # 注册
│   ├── ChangePassword()        error               # 修改密码
│   ├── VerifyToken()           (*Claims, error)    # 验证 JWT
│   ├── RefreshToken()          (string, error)     # 刷新 Token
│   └── GetUserByID()           (*User, error)      # 根据 ID 获取用户
│
├── monitor.go                  # 监控告警服务
│   ├── GetSystemStats()        (*SystemStats, error) # 系统统计
│   ├── GetNetworkStatus()      (*NetworkStatus, error) # 网络状态
│   ├── CheckAlertRules()       ([]Alert, error)    # 检查告警规则
│   ├── SendAlert()             error               # 发送告警
│   ├── ListAlertRules()        []AlertRule         # 告警规则列表
│   └── AddAlertRule()          error               # 添加告警规则
│
├── ddns.go                     # DDNS 服务
│   ├── SyncDDNS()              error               # 同步 DDNS 记录
│   ├── GetDDNSStatus()         (*DDNSStatus, error) # 获取状态
│   ├── RefreshDDNS()           error               # 刷新记录
│   ├── TestDNSProvider()       error               # 测试 DNS 服务商
│   └── GetDDNSHistory()        []DDNSRecord        # 历史记录
│
└── audit.go                    # 审计日志服务
    ├── LogAction()             error               # 记录操作日志
    ├── ListAuditLogs()         []AuditLog          # 查询日志
    ├── ExportAuditLogs()       ([]byte, error)     # 导出日志
    ├── GetAuditStats()         (*AuditStats, error) # 统计数据
    └── CleanOldLogs()          error               # 清理旧日志

📋 每个 Service 的职责详解

1. NetworkService - 组网管理

职责

  • 组网的创建、删除、更新
  • MeshSeed 的生成和解析
  • 网络配置的持久化
  • 调用 Ctr 执行实际操作

核心方法示例

// CreateNetwork 创建网络
func (s *NetworkService) CreateNetwork(req CreateNetworkRequest) (*Network, error) {
    // ① 业务规则校验
    if req.Name == "" {
        return nil, errors.New("组网名称不能为空")
    }
    
    // 检查名称是否重复
    var existing Network
    err := s.store.DB().Where("name = ?", req.Name).First(&existing).Error
    if err == nil {
        return nil, errors.New("组网名称已存在")
    }
    
    // ② 数据生成
    networkID := snowflake.Generate()
    secret := generateSecureSecret() // 32 字节随机
    
    // ③ 保存到数据库
    network := &model.Network{
        ID:         networkID,
        Name:       req.Name,
        Secret:     secret,
        Subnet:     req.Subnet,
        STUNServers: []string{"stun.l.google.com:19302"},
        CreatedAt:  time.Now(),
    }
    
    err = s.store.DB().Create(network).Error
    if err != nil {
        return nil, err
    }
    
    // ④ 调用 ctr 执行(事务外,失败需回滚)
    err = s.ctrClient.CreateNetwork(networkID, network.ToConfig())
    if err != nil {
        // 回滚:删除刚创建的 network
        s.store.DB().Delete(network)
        return nil, fmt.Errorf("调用 ctr 失败:%w", err)
    }
    
    return network, nil
}

// GenerateMeshSeed 生成组网凭证
func (s *NetworkService) GenerateMeshSeed(networkID uint64) (*MeshSeed, error) {
    // ① 查询网络信息
    var network model.Network
    err := s.store.DB().First(&network, networkID).Error
    if err != nil {
        return nil, errors.New("网络不存在")
    }
    
    // ② 生成 SeedID16 字节随机 Base64
    seedID := generateRandomBase64(16)
    
    // ③ Ed25519 签名
    signature := ed25519.Sign(privateKey, []byte(network.Secret))
    
    // ④ AES-GCM 加密配置
    ciphertext := aesGCM.Encrypt(network.ToJSON())
    
    // ⑤ 构建 MeshSeed
    meshSeed := &MeshSeed{
        SeedID:      seedID,
        NetworkID:   networkID,
        Signature:   signature,
        Ciphertext:  ciphertext,
        IssuedAt:    time.Now(),
        ExpiresAt:   time.Now().Add(365 * 24 * time.Hour),
    }
    
    // ⑥ 保存到数据库
    s.store.DB().Create(&model.MeshSeed{
        NetworkID: networkID,
        Data:      meshSeed.ToJSON(),
    })
    
    return meshSeed, nil
    // ✅ 完全不需要调用 ctr
}

2. DeviceService - 设备管理

职责

  • WireGuard 密钥对生成
  • 设备信息管理
  • WG 配置文件生成
  • 调用 Ctr 添加 Peer

核心方法示例

// AddDevice 添加设备
func (s *DeviceService) AddDevice(networkID uint64, name string) (*Device, error) {
    // ① 查询网络
    var network model.Network
    err := s.store.DB().First(&network, networkID).Error
    if err != nil {
        return nil, errors.New("网络不存在")
    }
    
    // ② 生成 WG 密钥对
    privateKey, publicKey, err := wgtypes.GenerateKey()
    if err != nil {
        return nil, err
    }
    
    // ③ 分配 IP(从子网中自动分配)
    ip := allocateIP(network.Subnet)
    
    // ④ 生成设备 ID
    deviceID := snowflake.Generate()
    
    // ⑤ 保存到数据库
    device := &model.Device{
        ID:         deviceID,
        NetworkID:  networkID,
        Name:       name,
        PublicKey:  publicKey.String(),
        PrivateKey: encryptPrivateKey(privateKey), // 加密存储
        IP:         ip,
        AllowedIPs: []string{ip + "/32"},
    }
    
    err = s.store.DB().Create(device).Error
    if err != nil {
        return nil, err
    }
    
    // ⑥ 调用 ctr 添加 Peer(可选,如果立即上线)
    if req.ImmediateConnect {
        err = s.ctrClient.AddPeer(networkID, device.PublicKey, device.AllowedIPs)
        if err != nil {
            s.store.DB().Delete(device)
            return nil, fmt.Errorf("调用 ctr 失败:%w", err)
        }
    }
    
    return device, nil
}

// GetDeviceConfig 获取设备配置(生成 WG 配置文件)
func (s *DeviceService) GetDeviceConfig(deviceID uint64) (string, error) {
    // ① 查询设备信息
    var device model.Device
    err := s.store.DB().Preload("Network").First(&device, deviceID).Error
    if err != nil {
        return "", errors.New("设备不存在")
    }
    
    // ② 解密私钥
    privateKey := decryptPrivateKey(device.PrivateKey)
    
    // ③ 生成 WG 配置
    config := fmt.Sprintf(`[Interface]
PrivateKey = %s
Address = %s
ListenPort = 51820

[Peer]
PublicKey = %s
AllowedIPs = %s
Endpoint = %s:51820
`, privateKey, device.IP, device.Network.PublicKey, device.AllowedIPs, device.Network.Endpoint)
    
    return config, nil
    // ✅ 纯业务逻辑,不需要调用 ctr!
}

3. UserService - 用户认证(完全不依赖 Ctr)

职责

  • 用户注册、登录
  • JWT Token 生成和验证
  • 密码加密存储
  • 审计日志记录

核心方法示例

// Login 用户登录
func (s *UserService) Login(username, password string) (string, error) {
    // ① 查询用户
    var user model.User
    err := s.store.DB().Where("username = ?", username).First(&user).Error
    if err != nil {
        return "", errors.New("用户名或密码错误")
    }
    
    // ② 验证密码(bcrypt
    err = bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password))
    if err != nil {
        return "", errors.New("用户名或密码错误")
    }
    
    // ③ 生成 JWT Token
    claims := jwt.Claims{
        UserID:   user.ID,
        Username: user.Username,
        Role:     user.Role,
    }
    token := jwt.GenerateToken(claims, jwtSecret, 24*time.Hour)
    
    // ④ 记录登录日志
    s.auditService.LogAction(user.ID, "login", "用户登录成功")
    
    return token, nil
    // ✅ 完全不需要调用 ctr
}

// Register 用户注册
func (s *UserService) Register(username, password, email string) error {
    // ① 检查用户名是否已存在
    var existing model.User
    err := s.store.DB().Where("username = ?", username).First(&existing).Error
    if err == nil {
        return errors.New("用户名已存在")
    }
    
    // ② 密码加密(bcrypt
    hash, err := bcrypt.GenerateFromPassword([]byte(password), 12)
    if err != nil {
        return err
    }
    
    // ③ 创建用户
    user := &model.User{
        Username:     username,
        Email:        email,
        PasswordHash: string(hash),
        Role:         "user",
    }
    
    err = s.store.DB().Create(user).Error
    if err != nil {
        return err
    }
    
    // ④ 记录注册日志
    s.auditService.LogAction(user.ID, "register", "用户注册成功")
    
    return nil
    // ✅ 完全不需要调用 ctr
}

4. PolicyService - 策略管理(部分依赖 Ctr)

职责

  • 9 层传输策略配置
  • 策略合法性校验
  • 策略持久化
  • 调用 Ctr 应用策略

核心方法示例

// SetPolicy 设置传输策略
func (s *PolicyService) SetPolicy(networkID uint64, policy PolicyConfig) error {
    // ① 业务规则校验
    if err := s.validatePolicy(policy); err != nil {
        return fmt.Errorf("策略配置不合法:%w", err)
    }
    
    // ② 保存到数据库
    policyModel := &model.Policy{
        NetworkID: networkID,
        Config:    policy.ToJSON(),
        UpdatedAt: time.Now(),
    }
    
    err := s.store.DB().Save(policyModel).Error
    if err != nil {
        return err
    }
    
    // ③ 调用 ctr 应用策略(可选,如果网络正在运行)
    if network.IsActive {
        err = s.ctrClient.UpdatePolicy(networkID, policy)
        if err != nil {
            return fmt.Errorf("应用策略失败:%w", err)
        }
    }
    
    return nil
}

// validatePolicy 验证策略合法性(纯业务逻辑)
func (s *PolicyService) validatePolicy(policy PolicyConfig) error {
    // 检查至少启用了一层
    if !policy.AnyLayerEnabled() {
        return errors.New("至少需要启用一层传输")
    }
    
    // 检查优先级顺序
    if !policy.IsValidOrder() {
        return errors.New("传输层优先级顺序不合法")
    }
    
    // 检查 STUN/TURN 服务器配置
    if policy.EnableDirectUDP && len(policy.STUNServers) == 0 {
        return errors.New("启用 Direct-UDP 需要配置 STUN 服务器")
    }
    
    if policy.EnableTURN && len(policy.TURNServers) == 0 {
        return errors.New("启用 TURN 需要配置 TURN 服务器")
    }
    
    return nil
    // ✅ 纯业务逻辑校验,不需要调用 ctr!
}

🔄 Service 层的通用模式

标准操作流程

func (s *XXXService) DoSomething(params Params) (Result, error) {
    // ① 业务规则校验
    if err := s.validate(params); err != nil {
        return nil, err
    }
    
    // ② 数据生成/转换
    data := generateData(params)
    
    // ③ 保存到数据库
    err := s.store.DB().Create(&data).Error
    if err != nil {
        return nil, err
    }
    
    // ④ 调用 ctr 执行(可选,放在事务外)
    err = s.ctrClient.DoSomething(data.ID, data.Config)
    if err != nil {
        // 回滚:删除刚创建的数据
        s.store.DB().Delete(&data)
        return nil, fmt.Errorf("调用 ctr 失败:%w", err)
    }
    
    return data, nil
}

不调用 Ctr 的场景

以下场景完全不需要调用 Ctr

  1. 用户认证Login/Register/VerifyToken
  2. 数据查询ListXXX/GetXXX
  3. 配置生成GenerateMeshSeed/GetDeviceConfig
  4. 策略校验ValidatePolicy
  5. 日志审计LogAction/ListAuditLogs
  6. 统计分析GetAuditStats/GetSystemStats

📊 Service 与 Ctr 的职责对比

维度 Service 层 Ctr 层
定位 业务逻辑核心 实时控制执行器
职责 业务规则、数据生成、持久化 执行 WG/Core 操作
依赖数据库 是(直接操作) 否(通过参数接收)
依赖 Ctr ⚠️ 部分依赖 不依赖 Service
主动性 主动发起调用 被动执行
可测试性 可 Mock Ctr 可独立测试
示例方法 CreateNetwork
Login
GenerateMeshSeed
CreateDevice
AddPeer
CreateEngine

总结

Service 层的核心价值

  1. 业务逻辑的承载者

    • 处理所有业务规则
    • 生成和转换数据
    • 持久化到数据库
  2. Ctr 层的调用者

    • 决定何时调用 Ctr
    • 传递必要的参数
    • 处理 Ctr 的返回结果
  3. 前后端的桥梁

    • 接收 API Handler 的请求
    • 返回处理结果给 Handler
    • 对外暴露完整的业务能力

设计原则

  • Service 层是核心:所有业务逻辑都在这里
  • Ctr 层是工具:只在需要实时控制时调用
  • 保持解耦Service 层可以独立于 Ctr 测试
  • 事务一致性Ctr 失败时需要回滚数据库

文档版本:v1.0
最后更新:2026-03-24
维护者:MeshRay Team