package handler import ( "net/http" "os" "os/exec" "time" "git.zkcoi.com/zkcoi/Meshray-Manager/internal/service" "github.com/gin-gonic/gin" "go.uber.org/zap" ) // SystemConfigHandler 系统配置处理器 type SystemConfigHandler struct { configService *service.SystemConfigService logger *zap.Logger } // NewSystemConfigHandler 创建系统配置处理器 func NewSystemConfigHandler(configService *service.SystemConfigService, logger *zap.Logger) *SystemConfigHandler { return &SystemConfigHandler{ configService: configService, logger: logger, } } // GetWGMode 获取当前 WG 运行模式 // @Summary 获取当前 WG 运行模式 // @Tags system-config // @Accept json // @Produce json // @Success 200 {object} object{wg_mode=string,wg_mode_display=string,actual_mode=string} // @Router /api/v1/system-config/wg-mode [get] func (h *SystemConfigHandler) GetWGMode(c *gin.Context) { // 获取配置的模式(用户设置) configMode, err := h.configService.GetWGMode() if err != nil { h.logger.Error("获取 WG 配置失败", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "获取失败"}) return } // ✅ 固定使用用户态模式 actualMode := "userspace" h.logger.Debug("WG 模式:固定使用 wireguard-go 用户态") c.JSON(http.StatusOK, gin.H{ "wg_mode": configMode, // 配置的模式(已废弃,保留兼容) "wg_mode_display": getModeDisplay(actualMode), // 实际运行的模式显示 "actual_mode": actualMode, // 实际运行的模式代码 }) } // getModeDisplay 获取模式的中文显示 func getModeDisplay(mode string) string { switch mode { case "kernel": return "内核态" case "userspace": return "用户态" default: return mode } } // SetWGMode 设置 WG 运行模式 // @Summary 设置 WG 运行模式(需要重启 MeshRay 才能生效) // @Tags system-config // @Accept json // @Produce json // @Param mode body object{mode string} true "WG 模式 (auto|kernel|userspace)" // @Success 200 {object} object{message=string} // @Router /api/v1/system-config/wg-mode [put] func (h *SystemConfigHandler) SetWGMode(c *gin.Context) { var req struct { Mode string `json:"mode"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误"}) return } if err := h.configService.SetWGMode(req.Mode); err != nil { h.logger.Error("设置 WG 模式失败", zap.Error(err)) c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } h.logger.Info("WG 模式已更新,需要重启 MeshRay 才能生效", zap.String("mode", req.Mode)) c.JSON(http.StatusOK, gin.H{ "message": "设置成功,请重启 MeshRay 使新配置生效", "wg_mode": req.Mode, }) } // ==================== 系统运维功能(P1/P2) ==================== // ChangePasswordRequest 修改密码请求 type ChangePasswordRequest struct { OldPassword string `json:"old_password"` NewPassword string `json:"new_password"` } // ChangePassword 修改密码(P1) func (h *SystemConfigHandler) ChangePassword(c *gin.Context) { var req ChangePasswordRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误"}) return } // 验证密码长度 if len(req.NewPassword) < 6 { c.JSON(http.StatusBadRequest, gin.H{"error": "密码至少 6 个字符"}) return } // 从上下文获取用户 ID userID, exists := c.Get("user_id") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "未认证"}) return } // 调用服务层修改密码 err := h.configService.ChangePassword(userID.(uint), req.OldPassword, req.NewPassword) if err != nil { h.logger.Error("修改密码失败", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } h.logger.Info("密码修改成功", zap.Uint("user_id", userID.(uint))) c.JSON(http.StatusOK, gin.H{"message": "密码修改成功"}) } // RestartCoreRequest 重启核心服务请求 type RestartCoreRequest struct { Graceful bool `json:"graceful"` // 是否优雅重启 } // RestartCore 重启核心服务(P1 - Windows 下通过重启进程实现) func (h *SystemConfigHandler) RestartCore(c *gin.Context) { var req RestartCoreRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误"}) return } h.logger.Info("收到重启核心服务请求", zap.Bool("graceful", req.Graceful)) // 获取当前可执行文件路径 execPath, err := os.Executable() if err != nil { h.logger.Error("获取可执行文件路径失败", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "无法获取程序路径"}) return } // 在后台启动新进程 cmd := exec.Command(execPath) if err := cmd.Start(); err != nil { h.logger.Error("启动新进程失败", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "重启失败"}) return } // 延迟退出,让新进程有时间启动 go func() { time.Sleep(2 * time.Second) os.Exit(0) }() h.logger.Info("核心服务将在 2 秒后重启") c.JSON(http.StatusOK, gin.H{"message": "核心服务正在重启..."}) }