package config import ( "fmt" "os" "strings" "github.com/go-playground/validator/v10" "github.com/spf13/viper" ) // ConfigLoader định nghĩa interface để load cấu hình type ConfigLoader interface { Load() (*Config, error) } // ViperConfigLoader triển khai ConfigLoader với Viper type ViperConfigLoader struct { configPaths []string configName string configType string envPrefix string } // NewConfigLoader tạo ConfigLoader mới với các giá trị mặc định func NewConfigLoader() ConfigLoader { return &ViperConfigLoader{ configPaths: []string{"./configs", ".", "./templates"}, configName: "config", configType: "yaml", envPrefix: "APP", } } // Load đọc cấu hình từ file và biến môi trường func (l *ViperConfigLoader) Load() (*Config, error) { // Khởi tạo viper v := viper.New() // Thiết lập tên config và loại v.SetConfigName(l.configName) v.SetConfigType(l.configType) // Thêm các paths để tìm config for _, path := range l.configPaths { v.AddConfigPath(path) } // Tự động đọc biến môi trường v.AutomaticEnv() v.SetEnvPrefix(l.envPrefix) v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) // Thiết lập giá trị mặc định setDefaultValues(v) // Đọc cấu hình if err := v.ReadInConfig(); err != nil { // Chỉ cảnh báo nếu không tìm thấy file, không gây lỗi if _, ok := err.(viper.ConfigFileNotFoundError); !ok { return nil, fmt.Errorf("error reading config file: %v", err) } } // Set default logger level if os.Getenv("LOG_LEVEL") == "" { if err := os.Setenv("LOG_LEVEL", "info"); err != nil { return nil, fmt.Errorf("failed to set LOG_LEVEL: %v", err) } } // Bind cấu hình vào struct var config Config if err := v.Unmarshal(&config); err != nil { return nil, fmt.Errorf("unable to decode config into struct: %v", err) } // Validate cấu hình if err := validateConfig(&config); err != nil { return nil, fmt.Errorf("config validation error: %v", err) } return &config, nil } // setDefaultValues thiết lập các giá trị mặc định cho config func setDefaultValues(v *viper.Viper) { // App defaults v.SetDefault("app.name", "GoStarter") v.SetDefault("app.version", "0.1.0") v.SetDefault("app.environment", "development") v.SetDefault("app.log_level", "info") v.SetDefault("app.timezone", "UTC") // Server defaults v.SetDefault("server.host", "0.0.0.0") v.SetDefault("server.port", 3000) v.SetDefault("server.read_timeout", 15) // seconds v.SetDefault("server.write_timeout", 15) // seconds v.SetDefault("server.shutdown_timeout", 30) // seconds v.SetDefault("server.trusted_proxies", []string{}) v.SetDefault("server.allow_origins", []string{"*"}) // Database defaults v.SetDefault("database.driver", "postgres") v.SetDefault("database.host", "localhost") v.SetDefault("database.port", 5432) v.SetDefault("database.max_open_conns", 25) v.SetDefault("database.max_idle_conns", 5) v.SetDefault("database.conn_max_lifetime", 300) // seconds v.SetDefault("database.ssl_mode", "disable") v.SetDefault("database.migration_path", "migrations") } // validateConfig xác thực cấu hình func validateConfig(config *Config) error { validate := validator.New() return validate.Struct(config) }