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

264 lines
7.1 KiB
Go

package handler
import (
"net/http"
"strconv"
"git.zkcoi.com/zkcoi/meshray/internal/api/dto"
"git.zkcoi.com/zkcoi/meshray/internal/model"
"git.zkcoi.com/zkcoi/meshray/internal/service"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// DeviceHandler 设备管理 Handler
type DeviceHandler struct {
deviceService *service.DeviceService
logger *zap.Logger
}
// NewDeviceHandler 创建设备处理器
func NewDeviceHandler(deviceService *service.DeviceService, logger *zap.Logger) *DeviceHandler {
return &DeviceHandler{
deviceService: deviceService,
logger: logger,
}
}
// CreateDevice 创建设备
// @Summary 在指定网络下创建设备
// @Tags devices
// @Accept json
// @Produce json
// @Param network_id path int true "网络 ID"
// @Param device body model.Device true "设备配置"
// @Success 200 {object} model.Device
// @Router /api/v1/networks/:network_id/devices [post]
func (h *DeviceHandler) CreateDevice(c *gin.Context) {
// 从 Query 参数获取 network_id
networkIDStr := c.Query("network_id")
networkID, err := strconv.ParseUint(networkIDStr, 10, 64)
if err != nil {
h.logger.Error("解析网络 ID 失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的网络 ID"})
return
}
var req service.CreateDeviceRequest
req.NetworkID = networkID
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误"})
return
}
// 使用 Service 层创建设备(返回完整配置)
result, err := h.deviceService.CreateDevice(&req)
if err != nil {
h.logger.Error("创建设备失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
h.logger.Info("设备创建成功",
zap.Uint64("id", result.Device.ID),
zap.String("name", result.Device.Name),
zap.Uint64("network_id", result.Device.NetworkID))
// 返回完整配置(包含私钥和 WG 配置)
c.JSON(http.StatusOK, gin.H{
"message": "设备创建成功",
"data": gin.H{
"device": result.Device,
"private_key": result.PrivateKey,
"wireguard_config": result.ConfigText,
},
})
}
// GetDevice 获取设备详情
// @Summary 获取设备详细信息
// @Tags devices
// @Accept json
// @Produce json
// @Param id path int true "设备 ID"
// @Success 200 {object} model.Device
// @Router /api/v1/devices/:id [get]
// GetDevice 获取设备详情
func (h *DeviceHandler) GetDevice(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
h.logger.Error("解析设备 ID 失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的设备 ID"})
return
}
device, err := h.deviceService.GetDevice(id)
if err != nil {
h.logger.Error("获取设备失败", zap.Error(err))
c.JSON(http.StatusNotFound, gin.H{"error": "设备不存在"})
return
}
// 使用 DTO 转换
resp := dto.ToDeviceResponse(device)
c.JSON(http.StatusOK, gin.H{
"data": resp,
})
}
// ListDevices 获取设备列表
// @Summary 获取指定网络下的设备列表
// @Tags devices
// @Accept json
// @Produce json
// @Param network_id path int true "网络 ID"
// @Success 200 {array} model.Device
// @Router /api/v1/networks/:network_id/devices [get]
// ListDevices 获取设备列表
func (h *DeviceHandler) ListDevices(c *gin.Context) {
networkIDStr := c.Query("network_id")
var devices []model.Device
var err error
if networkIDStr != "" {
networkID, err := strconv.ParseUint(networkIDStr, 10, 64)
if err != nil {
h.logger.Error("解析网络 ID 失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的网络 ID"})
return
}
devices, err = h.deviceService.ListDevicesByNetwork(networkID)
} else {
devices, err = h.deviceService.ListAllDevices()
}
if err != nil {
h.logger.Error("查询设备列表失败", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "查询失败"})
return
}
// 使用 DTO 批量转换
respList := dto.ToDeviceResponseList(devices)
c.JSON(http.StatusOK, gin.H{
"data": respList,
})
}
// UpdateDevice 更新设备
// @Summary 更新设备信息
// @Tags devices
// @Accept json
// @Produce json
// @Param id path int true "设备 ID"
// @Param device body model.Device true "设备配置"
// @Success 200 {object} model.Device
// @Router /api/v1/devices/:id [put]
func (h *DeviceHandler) UpdateDevice(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
h.logger.Error("解析设备 ID 失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的设备 ID"})
return
}
var req struct {
Name string `json:"name"`
VirtualIP string `json:"virtual_ip"`
Status string `json:"status"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误"})
return
}
// 构建更新字段
updates := make(map[string]interface{})
if req.Name != "" {
updates["name"] = req.Name
}
if req.VirtualIP != "" {
updates["virtual_ip"] = req.VirtualIP
}
if req.Status != "" {
updates["status"] = req.Status
}
// 使用 Service 层更新
device, err := h.deviceService.UpdateDevice(id, updates)
if err != nil {
h.logger.Error("更新设备失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
h.logger.Info("设备更新成功", zap.Uint64("id", device.ID))
c.JSON(http.StatusOK, gin.H{
"message": "更新成功",
"data": device,
})
}
// DeleteDevice 删除设备
// @Summary 删除指定设备
// @Tags devices
// @Accept json
// @Produce json
// @Param id path int true "设备 ID"
// @Success 200
// @Router /api/v1/devices/:id [delete]
func (h *DeviceHandler) DeleteDevice(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
h.logger.Error("解析设备 ID 失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的设备 ID"})
return
}
// 使用 Service 层删除
err = h.deviceService.DeleteDevice(id)
if err != nil {
h.logger.Error("删除设备失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
h.logger.Info("设备已删除", zap.Uint64("id", id))
c.JSON(http.StatusOK, gin.H{
"message": "删除成功",
})
}
// GenerateDeviceConfig 生成设备配置文件
// @Summary 生成 WireGuard 设备配置
// @Tags devices
// @Accept json
// @Produce json
// @Param id path int true "设备 ID"
// @Success 200 {string} string "配置文件内容"
// @Router /api/v1/devices/:id/config [get]
func (h *DeviceHandler) GenerateDeviceConfig(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
h.logger.Error("解析设备 ID 失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的设备 ID"})
return
}
// 调用 Service 层生成配置(包含密钥生成)
config, err := h.deviceService.GenerateDeviceConfig(id)
if err != nil {
h.logger.Error("生成配置失败", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.Data(http.StatusOK, "text/plain", []byte(config))
}