Initial commit
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
"git.zkcoi.com/zkcoi/meshray/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": "核心服务正在重启..."})
|
||||
}
|
||||
Reference in New Issue
Block a user