package web import ( "dhcp-dns-manager/internal/config" "encoding/json" "net/http" "sync" "github.com/gin-gonic/gin" ) // ConfigManager 配置管理器 type ConfigManager struct { configPath string config *config.Config mu sync.RWMutex } // NewConfigManager 创建配置管理器 func NewConfigManager(path string) (*ConfigManager, error) { cfg, err := config.LoadConfig(path) if err != nil { return nil, err } return &ConfigManager{ configPath: path, config: cfg, }, nil } // GetConfig 获取配置 func (cm *ConfigManager) GetConfig() *config.Config { cm.mu.RLock() defer cm.mu.RUnlock() return cm.config } // SaveConfig 保存配置 func (cm *ConfigManager) SaveConfig(cfg *config.Config) error { cm.mu.Lock() defer cm.mu.Unlock() cm.config = cfg return cfg.Save(cm.configPath) } // UpdateDHCPConfig 更新 DHCP 配置(支持部分更新) func (cm *ConfigManager) UpdateDHCPConfig(updates map[string]interface{}) error { cm.mu.Lock() defer cm.mu.Unlock() // 将更新合并到现有配置 for key, value := range updates { switch key { case "enabled": if v, ok := value.(bool); ok { cm.config.DHCP.Enabled = v } case "interface": if v, ok := value.(string); ok { cm.config.DHCP.Interface = v } case "network": if v, ok := value.(string); ok { cm.config.DHCP.Network = v } case "netmask": if v, ok := value.(string); ok { cm.config.DHCP.Netmask = v } case "gateway": if v, ok := value.(string); ok { cm.config.DHCP.Gateway = v } case "dns_servers": if v, ok := value.([]interface{}); ok { servers := make([]string, len(v)) for i, s := range v { servers[i] = s.(string) } cm.config.DHCP.DNSServers = servers } case "lease_time": if v, ok := value.(float64); ok { cm.config.DHCP.LeaseTime = int(v) } case "ip_pool_start": if v, ok := value.(string); ok { cm.config.DHCP.IPPoolStart = v } case "ip_pool_end": if v, ok := value.(string); ok { cm.config.DHCP.IPPoolEnd = v } case "domain_name": if v, ok := value.(string); ok { cm.config.DHCP.DomainName = v } case "ntp_servers": if v, ok := value.([]interface{}); ok { servers := make([]string, len(v)) for i, s := range v { servers[i] = s.(string) } cm.config.DHCP.NTPServers = servers } case "broadcast_address": if v, ok := value.(string); ok { cm.config.DHCP.BroadcastAddress = v } case "excluded_ips": if v, ok := value.([]interface{}); ok { ips := make([]string, len(v)) for i, ip := range v { ips[i] = ip.(string) } cm.config.DHCP.ExcludedIPs = ips } } } return cm.config.Save(cm.configPath) } // UpdateDNSConfig 更新 DNS 配置(支持部分更新) func (cm *ConfigManager) UpdateDNSConfig(updates map[string]interface{}) error { cm.mu.Lock() defer cm.mu.Unlock() for key, value := range updates { switch key { case "enabled": if v, ok := value.(bool); ok { cm.config.DNS.Enabled = v } case "listen_addr": if v, ok := value.(string); ok { cm.config.DNS.ListenAddr = v } case "listen_port": if v, ok := value.(float64); ok { cm.config.DNS.ListenPort = int(v) } case "upstream": if v, ok := value.([]interface{}); ok { servers := make([]string, len(v)) for i, s := range v { servers[i] = s.(string) } cm.config.DNS.Upstream = servers } case "cache_size": if v, ok := value.(float64); ok { cm.config.DNS.CacheSize = int(v) } case "cache_ttl": if v, ok := value.(float64); ok { cm.config.DNS.CacheTTL = int(v) } case "recursion": if v, ok := value.(bool); ok { cm.config.DNS.Recursion = v } } } return cm.config.Save(cm.configPath) } // handleGetDHCPConfig 获取 DHCP 配置 func (s *Server) handleGetDHCPConfig(c *gin.Context) { cm := c.MustGet("configManager").(*ConfigManager) cfg := cm.GetConfig() c.JSON(http.StatusOK, gin.H{"config": cfg.DHCP}) } // handleUpdateDHCPConfig 更新 DHCP 配置 func (s *Server) handleUpdateDHCPConfig(c *gin.Context) { cm := c.MustGet("configManager").(*ConfigManager) var updates map[string]interface{} if err := c.ShouldBindJSON(&updates); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON: " + err.Error()}) return } // 验证必填字段 if network, ok := updates["network"]; ok && network.(string) == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "network is required"}) return } if err := cm.UpdateDHCPConfig(updates); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Save failed: " + err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "DHCP config updated"}) } // handleGetDNSConfig 获取 DNS 配置 func (s *Server) handleGetDNSConfig(c *gin.Context) { cm := c.MustGet("configManager").(*ConfigManager) cfg := cm.GetConfig() c.JSON(http.StatusOK, gin.H{"config": cfg.DNS}) } // handleUpdateDNSConfig 更新 DNS 配置 func (s *Server) handleUpdateDNSConfig(c *gin.Context) { cm := c.MustGet("configManager").(*ConfigManager) var updates map[string]interface{} if err := c.ShouldBindJSON(&updates); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON: " + err.Error()}) return } // 验证端口 if port, ok := updates["listen_port"]; ok { if port.(float64) < 1 || port.(float64) > 65535 { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid port"}) return } } if err := cm.UpdateDNSConfig(updates); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Save failed: " + err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "DNS config updated"}) } // handleGetFullConfig 获取完整配置 func (s *Server) handleGetFullConfig(c *gin.Context) { cm := c.MustGet("configManager").(*ConfigManager) cfg := cm.GetConfig() c.JSON(http.StatusOK, gin.H{ "dhcp": cfg.DHCP, "dns": cfg.DNS, "web": cfg.Web, }) } // handleRestartService 重启服务 func (s *Server) handleRestartService(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "Restart requested. Please restart the service manually: sudo systemctl restart dhcp-dns-manager", }) } // ExportConfig 导出配置 func (s *Server) handleExportConfig(c *gin.Context) { cm := c.MustGet("configManager").(*ConfigManager) cfg := cm.GetConfig() c.Header("Content-Type", "application/json") c.Header("Content-Disposition", "attachment; filename=dhcp-dns-config.json") c.JSON(http.StatusOK, cfg) } // ImportConfig 导入配置 func (s *Server) handleImportConfig(c *gin.Context) { file, _, err := c.Request.FormFile("config") if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to upload config file"}) return } defer file.Close() var cfg config.Config if err := json.NewDecoder(file).Decode(&cfg); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid config file: " + err.Error()}) return } cm := c.MustGet("configManager").(*ConfigManager) if err := cm.SaveConfig(&cfg); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "Config imported successfully"}) }