package config import ( "fmt" "os" "strconv" "strings" "time" ) // Configuration 表示应用程序的完整配置 // 该结构体包含服务器、日志、安全和转换相关的所有配置项 type Configuration struct { // ServerConfig 服务器配置 Server ServerConfig `yaml:"server" json:"server"` // LoggingConfig 日志配置 Logging LoggingConfig `yaml:"logging" json:"logging"` // SecurityConfig 安全配置 Security SecurityConfig `yaml:"security" json:"security"` // ConversionConfig 转换配置 Conversion ConversionConfig `yaml:"conversion" json:"conversion"` } // ServerConfig 服务器相关配置 type ServerConfig struct { // Port 服务器监听端口,默认25500 Port int `yaml:"port" json:"port" env:"SUBCONVERTER_PORT" mapstructure:"port"` // Host 服务器监听地址,默认"0.0.0.0" Host string `yaml:"host" json:"host" env:"SUBCONVERTER_HOST" mapstructure:"host"` // ReadTimeout 读取超时时间(秒),默认30 ReadTimeout int `yaml:"read_timeout" json:"read_timeout" env:"SUBCONVERTER_READ_TIMEOUT" mapstructure:"read_timeout"` // WriteTimeout 写入超时时间(秒),默认30 WriteTimeout int `yaml:"write_timeout" json:"write_timeout" env:"SUBCONVERTER_WRITE_TIMEOUT" mapstructure:"write_timeout"` // MaxRequestSize 最大请求大小(字节),默认10MB MaxRequestSize int64 `yaml:"max_request_size" json:"max_request_size" env:"SUBCONVERTER_MAX_REQUEST_SIZE" mapstructure:"max_request_size"` } // Clone 创建服务器配置的深拷贝 func (s *ServerConfig) Clone() ServerConfig { if s == nil { return ServerConfig{} } return ServerConfig{ Port: s.Port, Host: s.Host, ReadTimeout: s.ReadTimeout, WriteTimeout: s.WriteTimeout, MaxRequestSize: s.MaxRequestSize, } } // LoggingConfig 日志相关配置 type LoggingConfig struct { // Level 日志级别,可选:debug, info, warn, error,默认info Level string `yaml:"level" json:"level" env:"SUBCONVERTER_LOG_LEVEL" mapstructure:"level"` // Format 日志格式,可选:json, text,默认json Format string `yaml:"format" json:"format" env:"SUBCONVERTER_LOG_FORMAT" mapstructure:"format"` // Output 日志输出,可选:stdout, stderr, file,默认stdout Output string `yaml:"output" json:"output" env:"SUBCONVERTER_LOG_OUTPUT" mapstructure:"output"` // File 如果Output为file,指定日志文件路径 File string `yaml:"file" json:"file" env:"SUBCONVERTER_LOG_FILE" mapstructure:"file"` } // Clone 创建日志配置的深拷贝 func (l *LoggingConfig) Clone() LoggingConfig { if l == nil { return LoggingConfig{} } return LoggingConfig{ Level: l.Level, Format: l.Format, Output: l.Output, File: l.File, } } // SecurityConfig 安全相关配置 type SecurityConfig struct { // AccessTokens 访问令牌列表,空列表表示无需认证 AccessTokens []string `yaml:"access_tokens" json:"access_tokens" env:"SUBCONVERTER_ACCESS_TOKENS" mapstructure:"access_tokens"` // CorsOrigins CORS允许的源列表,支持通配符* CorsOrigins []string `yaml:"cors_origins" json:"cors_origins" env:"SUBCONVERTER_CORS_ORIGINS" mapstructure:"cors_origins"` // RateLimit 速率限制(每分钟请求数),0表示不限制 RateLimit int `yaml:"rate_limit" json:"rate_limit" env:"SUBCONVERTER_RATE_LIMIT" mapstructure:"rate_limit"` // Timeout 请求超时时间(秒),默认60 Timeout int `yaml:"timeout" json:"timeout" env:"SUBCONVERTER_TIMEOUT" mapstructure:"timeout"` } // Clone 创建安全配置的深拷贝 func (s *SecurityConfig) Clone() SecurityConfig { if s == nil { return SecurityConfig{} } // 深拷贝切片 accessTokens := make([]string, len(s.AccessTokens)) copy(accessTokens, s.AccessTokens) corsOrigins := make([]string, len(s.CorsOrigins)) copy(corsOrigins, s.CorsOrigins) return SecurityConfig{ AccessTokens: accessTokens, CorsOrigins: corsOrigins, RateLimit: s.RateLimit, Timeout: s.Timeout, } } // ConversionConfig 转换相关配置 type ConversionConfig struct { // DefaultTarget 默认目标格式,默认clash DefaultTarget string `yaml:"default_target" json:"default_target" env:"SUBCONVERTER_DEFAULT_TARGET" mapstructure:"default_target"` // SupportedTargets 支持的目标格式列表 SupportedTargets []string `yaml:"supported_targets" json:"supported_targets" mapstructure:"supported_targets"` // DefaultEmoji 默认是否启用emoji,默认false DefaultEmoji bool `yaml:"default_emoji" json:"default_emoji" env:"SUBCONVERTER_DEFAULT_EMOJI" mapstructure:"default_emoji"` // DefaultUDP 默认是否启用UDP,默认false DefaultUDP bool `yaml:"default_udp" json:"default_udp" env:"SUBCONVERTER_DEFAULT_UDP" mapstructure:"default_udp"` // MaxNodes 最大节点数量,默认0(无限制) MaxNodes int `yaml:"max_nodes" json:"max_nodes" env:"SUBCONVERTER_MAX_NODES" mapstructure:"max_nodes"` // CacheTimeout 缓存超时时间(分钟),默认60 CacheTimeout int `yaml:"cache_timeout" json:"cache_timeout" env:"SUBCONVERTER_CACHE_TIMEOUT" mapstructure:"cache_timeout"` } // Clone 创建转换配置的深拷贝 func (c *ConversionConfig) Clone() ConversionConfig { if c == nil { return ConversionConfig{} } // 深拷贝切片 supportedTargets := make([]string, len(c.SupportedTargets)) copy(supportedTargets, c.SupportedTargets) return ConversionConfig{ DefaultTarget: c.DefaultTarget, SupportedTargets: supportedTargets, DefaultEmoji: c.DefaultEmoji, DefaultUDP: c.DefaultUDP, MaxNodes: c.MaxNodes, CacheTimeout: c.CacheTimeout, } } // NewConfiguration 创建新的默认配置 // 返回包含所有默认值的Configuration结构体 func NewConfiguration() *Configuration { return &Configuration{ Server: ServerConfig{ Port: 25500, Host: "0.0.0.0", ReadTimeout: 30, WriteTimeout: 30, MaxRequestSize: 10 * 1024 * 1024, // 10MB }, Logging: LoggingConfig{ Level: "info", Format: "json", Output: "stdout", File: "", }, Security: SecurityConfig{ AccessTokens: []string{}, CorsOrigins: []string{"*"}, RateLimit: 0, Timeout: 60, }, Conversion: ConversionConfig{ DefaultTarget: "clash", SupportedTargets: []string{"clash", "clashr", "surge", "quanx", "loon", "surfboard", "v2ray"}, DefaultEmoji: false, DefaultUDP: false, MaxNodes: 0, CacheTimeout: 60, }, } } // Validate 验证配置的有效性 // 返回error如果配置无效,nil表示配置有效 func (c *Configuration) Validate() error { // 验证服务器配置 if c.Server.Port < 1 || c.Server.Port > 65535 { return fmt.Errorf("server port must be between 1 and 65535, got: %d", c.Server.Port) } if c.Server.Host == "" { return fmt.Errorf("server host cannot be empty") } if c.Server.ReadTimeout < 1 { return fmt.Errorf("read timeout must be positive, got: %d", c.Server.ReadTimeout) } if c.Server.WriteTimeout < 1 { return fmt.Errorf("write timeout must be positive, got: %d", c.Server.WriteTimeout) } if c.Server.MaxRequestSize < 1 { return fmt.Errorf("max request size must be positive, got: %d", c.Server.MaxRequestSize) } // 验证日志配置 validLogLevels := map[string]bool{ "debug": true, "info": true, "warn": true, "error": true, } if !validLogLevels[c.Logging.Level] { return fmt.Errorf("log level must be one of: debug, info, warn, error, got: %s", c.Logging.Level) } validLogFormats := map[string]bool{ "json": true, "text": true, } if !validLogFormats[c.Logging.Format] { return fmt.Errorf("log format must be one of: json, text, got: %s", c.Logging.Format) } validOutputs := map[string]bool{ "stdout": true, "stderr": true, "file": true, } if !validOutputs[c.Logging.Output] { return fmt.Errorf("log output must be one of: stdout, stderr, file, got: %s", c.Logging.Output) } if c.Logging.Output == "file" && c.Logging.File == "" { return fmt.Errorf("log file path must be specified when output is file") } // 验证安全配置 if c.Security.Timeout < 1 { return fmt.Errorf("timeout must be positive, got: %d", c.Security.Timeout) } if c.Security.RateLimit < 0 { return fmt.Errorf("rate limit must be non-negative, got: %d", c.Security.RateLimit) } // 验证转换配置 if !contains(c.Conversion.SupportedTargets, c.Conversion.DefaultTarget) { return fmt.Errorf("default target must be in supported targets, got: %s", c.Conversion.DefaultTarget) } if c.Conversion.MaxNodes < 0 { return fmt.Errorf("max nodes must be non-negative, got: %d", c.Conversion.MaxNodes) } if c.Conversion.CacheTimeout < 0 { return fmt.Errorf("cache timeout must be non-negative, got: %d", c.Conversion.CacheTimeout) } return nil } // Clone 创建配置的深拷贝 // 返回配置的独立副本 func (c *Configuration) Clone() *Configuration { if c == nil { return nil } clone := &Configuration{ Server: c.Server.Clone(), Logging: c.Logging.Clone(), Security: c.Security.Clone(), Conversion: c.Conversion.Clone(), } return clone } // LoadFromEnvironment 从环境变量加载配置 // 根据环境变量覆盖默认配置值 func (c *Configuration) LoadFromEnvironment() { // 服务器配置 if port := os.Getenv("SUBCONVERTER_PORT"); port != "" { if p, err := strconv.Atoi(port); err == nil { c.Server.Port = p } } if host := os.Getenv("SUBCONVERTER_HOST"); host != "" { c.Server.Host = host } if readTimeout := os.Getenv("SUBCONVERTER_READ_TIMEOUT"); readTimeout != "" { if rt, err := strconv.Atoi(readTimeout); err == nil { c.Server.ReadTimeout = rt } } if writeTimeout := os.Getenv("SUBCONVERTER_WRITE_TIMEOUT"); writeTimeout != "" { if wt, err := strconv.Atoi(writeTimeout); err == nil { c.Server.WriteTimeout = wt } } // 日志配置 if logLevel := os.Getenv("SUBCONVERTER_LOG_LEVEL"); logLevel != "" { c.Logging.Level = logLevel } if logFormat := os.Getenv("SUBCONVERTER_LOG_FORMAT"); logFormat != "" { c.Logging.Format = logFormat } if logOutput := os.Getenv("SUBCONVERTER_LOG_OUTPUT"); logOutput != "" { c.Logging.Output = logOutput } if logFile := os.Getenv("SUBCONVERTER_LOG_FILE"); logFile != "" { c.Logging.File = logFile } // 安全配置 if accessTokens := os.Getenv("SUBCONVERTER_ACCESS_TOKENS"); accessTokens != "" { c.Security.AccessTokens = strings.Split(accessTokens, ",") } if corsOrigins := os.Getenv("SUBCONVERTER_CORS_ORIGINS"); corsOrigins != "" { c.Security.CorsOrigins = strings.Split(corsOrigins, ",") } if rateLimit := os.Getenv("SUBCONVERTER_RATE_LIMIT"); rateLimit != "" { if rl, err := strconv.Atoi(rateLimit); err == nil { c.Security.RateLimit = rl } } if timeout := os.Getenv("SUBCONVERTER_TIMEOUT"); timeout != "" { if t, err := strconv.Atoi(timeout); err == nil { c.Security.Timeout = t } } // 转换配置 if defaultTarget := os.Getenv("SUBCONVERTER_DEFAULT_TARGET"); defaultTarget != "" { c.Conversion.DefaultTarget = defaultTarget } if defaultEmoji := os.Getenv("SUBCONVERTER_DEFAULT_EMOJI"); defaultEmoji != "" { if de, err := strconv.ParseBool(defaultEmoji); err == nil { c.Conversion.DefaultEmoji = de } } if defaultUDP := os.Getenv("SUBCONVERTER_DEFAULT_UDP"); defaultUDP != "" { if du, err := strconv.ParseBool(defaultUDP); err == nil { c.Conversion.DefaultUDP = du } } if maxNodes := os.Getenv("SUBCONVERTER_MAX_NODES"); maxNodes != "" { if mn, err := strconv.Atoi(maxNodes); err == nil { c.Conversion.MaxNodes = mn } } if cacheTimeout := os.Getenv("SUBCONVERTER_CACHE_TIMEOUT"); cacheTimeout != "" { if ct, err := strconv.Atoi(cacheTimeout); err == nil { c.Conversion.CacheTimeout = ct } } } // GetServerAddress 返回服务器地址字符串 // 格式为 "host:port" func (c *Configuration) GetServerAddress() string { return fmt.Sprintf("%s:%d", c.Server.Host, c.Server.Port) } // GetReadTimeoutDuration 返回读取超时时间duration func (c *Configuration) GetReadTimeoutDuration() time.Duration { return time.Duration(c.Server.ReadTimeout) * time.Second } // GetWriteTimeoutDuration 返回写入超时时间duration func (c *Configuration) GetWriteTimeoutDuration() time.Duration { return time.Duration(c.Server.WriteTimeout) * time.Second } // GetTimeoutDuration 返回请求超时时间duration func (c *Configuration) GetTimeoutDuration() time.Duration { return time.Duration(c.Security.Timeout) * time.Second } // GetCacheTimeoutDuration 返回缓存超时时间duration func (c *Configuration) GetCacheTimeoutDuration() time.Duration { return time.Duration(c.Conversion.CacheTimeout) * time.Minute } // IsAccessTokenValid 检查访问令牌是否有效 func (c *Configuration) IsAccessTokenValid(token string) bool { if len(c.Security.AccessTokens) == 0 { return true // 空列表表示无需认证 } return contains(c.Security.AccessTokens, token) } // IsCorsOriginAllowed 检查CORS源是否允许 func (c *Configuration) IsCorsOriginAllowed(origin string) bool { for _, allowed := range c.Security.CorsOrigins { if allowed == "*" || allowed == origin { return true } } return false } // IsTargetSupported 检查目标格式是否支持 func (c *Configuration) IsTargetSupported(target string) bool { return contains(c.Conversion.SupportedTargets, target) } // contains 检查字符串切片是否包含特定字符串 func contains(slice []string, item string) bool { for _, s := range slice { if s == item { return true } } return false }