mirror of
https://github.com/p-box2025/P-BOX.git
synced 2026-05-13 15:47:40 +08:00
306 lines
6.4 KiB
Go
306 lines
6.4 KiB
Go
package proxy
|
||
|
||
import (
|
||
"encoding/json"
|
||
"net/http"
|
||
"os"
|
||
"path/filepath"
|
||
"sync"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"gopkg.in/yaml.v3"
|
||
)
|
||
|
||
// SettingsHandler 代理设置处理器
|
||
type SettingsHandler struct {
|
||
dataDir string
|
||
settings *ProxySettings
|
||
mu sync.RWMutex
|
||
proxyService *Service // 代理服务引用,用于同步配置
|
||
}
|
||
|
||
// NewSettingsHandler 创建设置处理器
|
||
func NewSettingsHandler(dataDir string) *SettingsHandler {
|
||
h := &SettingsHandler{
|
||
dataDir: dataDir,
|
||
settings: GetDefaultProxySettings(),
|
||
}
|
||
// 加载已保存的设置
|
||
h.loadSettings()
|
||
return h
|
||
}
|
||
|
||
// SetProxyService 设置代理服务引用
|
||
func (h *SettingsHandler) SetProxyService(s *Service) {
|
||
h.proxyService = s
|
||
}
|
||
|
||
// RegisterRoutes 注册路由
|
||
func (h *SettingsHandler) RegisterRoutes(r *gin.RouterGroup) {
|
||
r.GET("/settings", h.GetSettings)
|
||
r.PUT("/settings", h.UpdateSettings)
|
||
r.POST("/settings/reset", h.ResetSettings)
|
||
r.GET("/settings/presets", h.GetPresets)
|
||
r.POST("/settings/apply-preset", h.ApplyPreset)
|
||
}
|
||
|
||
// settingsFilePath 获取设置文件路径
|
||
func (h *SettingsHandler) settingsFilePath() string {
|
||
return filepath.Join(h.dataDir, "proxy_settings.yaml")
|
||
}
|
||
|
||
// loadSettings 加载设置
|
||
func (h *SettingsHandler) loadSettings() error {
|
||
h.mu.Lock()
|
||
defer h.mu.Unlock()
|
||
|
||
data, err := os.ReadFile(h.settingsFilePath())
|
||
if err != nil {
|
||
if os.IsNotExist(err) {
|
||
// 文件不存在,使用默认设置
|
||
return nil
|
||
}
|
||
return err
|
||
}
|
||
|
||
var settings ProxySettings
|
||
if err := yaml.Unmarshal(data, &settings); err != nil {
|
||
return err
|
||
}
|
||
|
||
// 设置默认值(旧配置文件可能缺少新字段)
|
||
if settings.AutoStartDelay == 0 {
|
||
settings.AutoStartDelay = 15 // 默认延迟 15 秒
|
||
}
|
||
|
||
h.settings = &settings
|
||
return nil
|
||
}
|
||
|
||
// saveSettings 保存设置
|
||
func (h *SettingsHandler) saveSettings() error {
|
||
data, err := yaml.Marshal(h.settings)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 确保目录存在
|
||
dir := filepath.Dir(h.settingsFilePath())
|
||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||
return err
|
||
}
|
||
|
||
return os.WriteFile(h.settingsFilePath(), data, 0644)
|
||
}
|
||
|
||
// GetSettings 获取当前设置
|
||
func (h *SettingsHandler) GetSettings(c *gin.Context) {
|
||
h.mu.RLock()
|
||
defer h.mu.RUnlock()
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 0,
|
||
"data": h.settings,
|
||
})
|
||
}
|
||
|
||
// UpdateSettings 更新设置
|
||
func (h *SettingsHandler) UpdateSettings(c *gin.Context) {
|
||
var settings ProxySettings
|
||
if err := c.ShouldBindJSON(&settings); err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{
|
||
"code": 1,
|
||
"message": "Invalid settings: " + err.Error(),
|
||
})
|
||
return
|
||
}
|
||
|
||
h.mu.Lock()
|
||
h.settings = &settings
|
||
err := h.saveSettings()
|
||
h.mu.Unlock()
|
||
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{
|
||
"code": 1,
|
||
"message": "Failed to save settings: " + err.Error(),
|
||
})
|
||
return
|
||
}
|
||
|
||
// 同步到 proxy 服务
|
||
if h.proxyService != nil {
|
||
h.proxyService.PatchConfig(map[string]interface{}{
|
||
"autoStart": settings.AutoStart,
|
||
"autoStartDelay": float64(settings.AutoStartDelay),
|
||
})
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 0,
|
||
"message": "Settings updated successfully",
|
||
})
|
||
}
|
||
|
||
// ResetSettings 重置为默认设置
|
||
func (h *SettingsHandler) ResetSettings(c *gin.Context) {
|
||
h.mu.Lock()
|
||
h.settings = GetDefaultProxySettings()
|
||
err := h.saveSettings()
|
||
h.mu.Unlock()
|
||
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{
|
||
"code": 1,
|
||
"message": "Failed to save settings: " + err.Error(),
|
||
})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 0,
|
||
"message": "Settings reset to defaults",
|
||
"data": h.settings,
|
||
})
|
||
}
|
||
|
||
// SettingsPreset 设置预设
|
||
type SettingsPreset struct {
|
||
ID string `json:"id"`
|
||
Name string `json:"name"`
|
||
Description string `json:"description"`
|
||
Icon string `json:"icon"`
|
||
}
|
||
|
||
// GetPresets 获取预设列表
|
||
func (h *SettingsHandler) GetPresets(c *gin.Context) {
|
||
presets := []SettingsPreset{
|
||
{
|
||
ID: "gateway",
|
||
Name: "Linux 网关",
|
||
Description: "软路由/旁路由模式,TUN+DNS 最佳性能",
|
||
Icon: "server",
|
||
},
|
||
{
|
||
ID: "desktop",
|
||
Name: "桌面客户端",
|
||
Description: "Windows/macOS 系统代理模式",
|
||
Icon: "monitor",
|
||
},
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 0,
|
||
"data": presets,
|
||
})
|
||
}
|
||
|
||
// ApplyPreset 应用预设
|
||
func (h *SettingsHandler) ApplyPreset(c *gin.Context) {
|
||
var req struct {
|
||
PresetID string `json:"presetId"`
|
||
}
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, gin.H{
|
||
"code": 1,
|
||
"message": "Invalid request",
|
||
})
|
||
return
|
||
}
|
||
|
||
h.mu.Lock()
|
||
defer h.mu.Unlock()
|
||
|
||
switch req.PresetID {
|
||
case "gateway":
|
||
h.settings = getGatewayPreset()
|
||
case "desktop":
|
||
h.settings = getDesktopPreset()
|
||
default:
|
||
c.JSON(http.StatusBadRequest, gin.H{
|
||
"code": 1,
|
||
"message": "Unknown preset: " + req.PresetID,
|
||
})
|
||
return
|
||
}
|
||
|
||
if err := h.saveSettings(); err != nil {
|
||
c.JSON(http.StatusInternalServerError, gin.H{
|
||
"code": 1,
|
||
"message": "Failed to save settings",
|
||
})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"code": 0,
|
||
"message": "Preset applied successfully",
|
||
"data": h.settings,
|
||
})
|
||
}
|
||
|
||
// GetCurrentSettings 获取当前设置(供其他模块调用)
|
||
func (h *SettingsHandler) GetCurrentSettings() *ProxySettings {
|
||
h.mu.RLock()
|
||
defer h.mu.RUnlock()
|
||
|
||
// 返回副本
|
||
data, _ := json.Marshal(h.settings)
|
||
var copy ProxySettings
|
||
json.Unmarshal(data, ©)
|
||
return ©
|
||
}
|
||
|
||
// === 预设配置 ===
|
||
|
||
// getGatewayPreset Linux 网关预设
|
||
func getGatewayPreset() *ProxySettings {
|
||
s := GetDefaultProxySettings()
|
||
// 网关模式优化
|
||
s.AllowLan = true
|
||
s.BindAddress = "*"
|
||
s.FindProcessMode = "off" // 关闭进程匹配
|
||
s.TCPConcurrent = true
|
||
s.UnifiedDelay = true
|
||
s.GeodataMode = true
|
||
s.GeodataLoader = "standard"
|
||
|
||
// TUN 模式
|
||
s.TUN.Enable = true
|
||
s.TUN.Stack = "mixed"
|
||
s.TUN.MTU = 9000
|
||
s.TUN.GSO = true
|
||
s.TUN.AutoRoute = true
|
||
s.TUN.AutoRedirect = true
|
||
s.TUN.StrictRoute = true
|
||
s.TUN.EndpointIndependentNat = true
|
||
|
||
// DNS
|
||
s.DNS.Enable = true
|
||
s.DNS.Listen = "0.0.0.0:53"
|
||
s.DNS.EnhancedMode = "fake-ip"
|
||
s.DNS.RespectRules = true
|
||
|
||
return s
|
||
}
|
||
|
||
// getDesktopPreset 桌面客户端预设
|
||
func getDesktopPreset() *ProxySettings {
|
||
s := GetDefaultProxySettings()
|
||
s.AllowLan = false
|
||
s.BindAddress = "127.0.0.1"
|
||
s.FindProcessMode = "strict"
|
||
s.TCPConcurrent = true
|
||
s.UnifiedDelay = true
|
||
|
||
// TUN 关闭(使用系统代理)
|
||
s.TUN.Enable = false
|
||
|
||
// DNS
|
||
s.DNS.Enable = true
|
||
s.DNS.Listen = "127.0.0.1:1053"
|
||
s.DNS.EnhancedMode = "fake-ip"
|
||
|
||
return s
|
||
}
|