264 lines
7.1 KiB
Go
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))
|
|
}
|