Initial commit

This commit is contained in:
2026-06-30 15:14:37 +08:00
commit 15dab96872
311 changed files with 95639 additions and 0 deletions
+177
View File
@@ -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": "核心服务正在重启..."})
}