Files
zkcoi e9ca2f7d70 fix: rename manager module to git.zkcoi.com/zkcoi/Meshray-Manager
- go.mod module path matches repo zkcoi/Meshray-Manager (case-distinct from zkcoi/Meshray/core)
- rewrite internal imports meshray/{internal,web,pkg} -> Meshray-Manager/... (core refs kept)
- sync README.md / install.sh repo URLs; add CHANGELOG entry
2026-07-15 16:25:46 +08:00

178 lines
5.2 KiB
Go
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.
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": "核心服务正在重启..."})
}