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

569 lines
19 KiB
Markdown
Raw Permalink 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.
# 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 执行实际操作
**核心方法示例**
```go
// 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
**核心方法示例**
```go
// 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 生成和验证
- ✅ 密码加密存储
- ✅ 审计日志记录
**核心方法示例**
```go
// 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 应用策略
**核心方法示例**
```go
// 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 层的通用模式
### **标准操作流程**
```go
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<br>Login<br>GenerateMeshSeed | CreateDevice<br>AddPeer<br>CreateEngine |
---
## ✅ 总结
### **Service 层的核心价值**
1.**业务逻辑的承载者**
- 处理所有业务规则
- 生成和转换数据
- 持久化到数据库
2.**Ctr 层的调用者**
- 决定何时调用 Ctr
- 传递必要的参数
- 处理 Ctr 的返回结果
3.**前后端的桥梁**
- 接收 API Handler 的请求
- 返回处理结果给 Handler
- 对外暴露完整的业务能力
### **设计原则**
-**Service 层是核心**:所有业务逻辑都在这里
-**Ctr 层是工具**:只在需要实时控制时调用
-**保持解耦**Service 层可以独立于 Ctr 测试
-**事务一致性**Ctr 失败时需要回滚数据库
---
*文档版本:v1.0*
*最后更新:2026-03-24*
*维护者:MeshRay Team*