// Package config provides configuration management for the application package config import ( "fmt" "os" "strings" "gpt-load/internal/errors" "gpt-load/internal/types" "gpt-load/internal/utils" "github.com/joho/godotenv" "github.com/sirupsen/logrus" ) // Constants represents configuration constants type Constants struct { MinPort int MaxPort int MinTimeout int DefaultTimeout int DefaultMaxSockets int DefaultMaxFreeSockets int } // DefaultConstants holds default configuration values var DefaultConstants = Constants{ MinPort: 1, MaxPort: 65535, MinTimeout: 1, DefaultTimeout: 30, DefaultMaxSockets: 50, DefaultMaxFreeSockets: 10, } // Manager implements the ConfigManager interface type Manager struct { config *Config settingsManager *SystemSettingsManager } // Config represents the application configuration type Config struct { Server types.ServerConfig `json:"server"` Auth types.AuthConfig `json:"auth"` CORS types.CORSConfig `json:"cors"` Performance types.PerformanceConfig `json:"performance"` Log types.LogConfig `json:"log"` Database types.DatabaseConfig `json:"database"` RedisDSN string `json:"redis_dsn"` } // NewManager creates a new configuration manager func NewManager(settingsManager *SystemSettingsManager) (types.ConfigManager, error) { manager := &Manager{ settingsManager: settingsManager, } if err := manager.ReloadConfig(); err != nil { return nil, err } return manager, nil } // ReloadConfig reloads the configuration from environment variables func (m *Manager) ReloadConfig() error { if err := godotenv.Load(); err != nil { logrus.Info("Info: Create .env file to support environment variable configuration") } config := &Config{ Server: types.ServerConfig{ Port: utils.ParseInteger(os.Getenv("PORT"), 3000), Host: utils.GetEnvOrDefault("HOST", "0.0.0.0"), ReadTimeout: utils.ParseInteger(os.Getenv("SERVER_READ_TIMEOUT"), 120), WriteTimeout: utils.ParseInteger(os.Getenv("SERVER_WRITE_TIMEOUT"), 1800), IdleTimeout: utils.ParseInteger(os.Getenv("SERVER_IDLE_TIMEOUT"), 120), GracefulShutdownTimeout: utils.ParseInteger(os.Getenv("SERVER_GRACEFUL_SHUTDOWN_TIMEOUT"), 60), }, Auth: types.AuthConfig{ Key: os.Getenv("AUTH_KEY"), }, CORS: types.CORSConfig{ Enabled: utils.ParseBoolean(os.Getenv("ENABLE_CORS"), true), AllowedOrigins: utils.ParseArray(os.Getenv("ALLOWED_ORIGINS"), []string{"*"}), AllowedMethods: utils.ParseArray(os.Getenv("ALLOWED_METHODS"), []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}), AllowedHeaders: utils.ParseArray(os.Getenv("ALLOWED_HEADERS"), []string{"*"}), AllowCredentials: utils.ParseBoolean(os.Getenv("ALLOW_CREDENTIALS"), false), }, Performance: types.PerformanceConfig{ MaxConcurrentRequests: utils.ParseInteger(os.Getenv("MAX_CONCURRENT_REQUESTS"), 100), }, Log: types.LogConfig{ Level: utils.GetEnvOrDefault("LOG_LEVEL", "info"), Format: utils.GetEnvOrDefault("LOG_FORMAT", "text"), EnableFile: utils.ParseBoolean(os.Getenv("LOG_ENABLE_FILE"), false), FilePath: utils.GetEnvOrDefault("LOG_FILE_PATH", "logs/app.log"), }, Database: types.DatabaseConfig{ DSN: os.Getenv("DATABASE_DSN"), }, RedisDSN: os.Getenv("REDIS_DSN"), } m.config = config // Validate configuration if err := m.Validate(); err != nil { return err } return nil } // GetAuthConfig returns authentication configuration func (m *Manager) GetAuthConfig() types.AuthConfig { return m.config.Auth } // GetCORSConfig returns CORS configuration func (m *Manager) GetCORSConfig() types.CORSConfig { return m.config.CORS } // GetPerformanceConfig returns performance configuration func (m *Manager) GetPerformanceConfig() types.PerformanceConfig { return m.config.Performance } // GetLogConfig returns logging configuration func (m *Manager) GetLogConfig() types.LogConfig { return m.config.Log } // GetRedisDSN returns the Redis DSN string. func (m *Manager) GetRedisDSN() string { return m.config.RedisDSN } // GetDatabaseConfig returns the database configuration. func (m *Manager) GetDatabaseConfig() types.DatabaseConfig { return m.config.Database } // GetEffectiveServerConfig returns server configuration merged with system settings func (m *Manager) GetEffectiveServerConfig() types.ServerConfig { return m.config.Server } // Validate validates the configuration func (m *Manager) Validate() error { var validationErrors []string // Validate port if m.config.Server.Port < DefaultConstants.MinPort || m.config.Server.Port > DefaultConstants.MaxPort { validationErrors = append(validationErrors, fmt.Sprintf("port must be between %d-%d", DefaultConstants.MinPort, DefaultConstants.MaxPort)) } if m.config.Performance.MaxConcurrentRequests < 1 { validationErrors = append(validationErrors, "max concurrent requests cannot be less than 1") } // Validate auth key if m.config.Auth.Key == "" { validationErrors = append(validationErrors, "AUTH_KEY is required and cannot be empty") } // Validate GracefulShutdownTimeout and reset if necessary if m.config.Server.GracefulShutdownTimeout < 10 { logrus.Warnf("SERVER_GRACEFUL_SHUTDOWN_TIMEOUT value %ds is too short, resetting to minimum 10s.", m.config.Server.GracefulShutdownTimeout) m.config.Server.GracefulShutdownTimeout = 10 } if len(validationErrors) > 0 { logrus.Error("Configuration validation failed:") for _, err := range validationErrors { logrus.Errorf(" - %s", err) } return errors.NewAPIError(errors.ErrValidation, strings.Join(validationErrors, "; ")) } return nil } // DisplayServerConfig displays current server-related configuration information func (m *Manager) DisplayServerConfig() { serverConfig := m.GetEffectiveServerConfig() corsConfig := m.GetCORSConfig() perfConfig := m.GetPerformanceConfig() logConfig := m.GetLogConfig() dbConfig := m.GetDatabaseConfig() logrus.Info("--- Server Configuration ---") logrus.Infof(" Listen Address: %s:%d", serverConfig.Host, serverConfig.Port) logrus.Infof(" Graceful Shutdown Timeout: %d seconds", serverConfig.GracefulShutdownTimeout) logrus.Infof(" Read Timeout: %d seconds", serverConfig.ReadTimeout) logrus.Infof(" Write Timeout: %d seconds", serverConfig.WriteTimeout) logrus.Infof(" Idle Timeout: %d seconds", serverConfig.IdleTimeout) logrus.Info("--- Performance ---") logrus.Infof(" Max Concurrent Requests: %d", perfConfig.MaxConcurrentRequests) logrus.Info("--- Security ---") logrus.Infof(" Authentication: enabled (key loaded)") corsStatus := "disabled" if corsConfig.Enabled { corsStatus = fmt.Sprintf("enabled (Origins: %s)", strings.Join(corsConfig.AllowedOrigins, ", ")) } logrus.Infof(" CORS: %s", corsStatus) logrus.Info("--- Logging ---") logrus.Infof(" Log Level: %s", logConfig.Level) logrus.Infof(" Log Format: %s", logConfig.Format) logrus.Infof(" File Logging: %t", logConfig.EnableFile) if logConfig.EnableFile { logrus.Infof(" Log File Path: %s", logConfig.FilePath) } logrus.Info("--- Dependencies ---") if dbConfig.DSN != "" { logrus.Info(" Database: configured") } else { logrus.Info(" Database: not configured") } if m.config.RedisDSN != "" { logrus.Info(" Redis: configured") } else { logrus.Info(" Redis: not configured") } logrus.Info("--------------------------") }