package config import ( "log" "os" "path/filepath" "time" "github.com/kelseyhightower/envconfig" "github.com/spf13/viper" ) const ( defaultHTTPPort = "8000" defaultHTTPRWTimeout = 10 * time.Second defaultHTTPMaxHeaderMegabytes = 1 defaultAccessTokenTTL = 15 * time.Minute defaultRefreshTokenTTL = 24 * time.Hour * 30 defaultLimiterRPS = 10 defaultLimiterBurst = 2 defaultLimiterTTL = 10 * time.Minute defaultVerificationCodeLength = 8 EnvLocal = "local" Prod = "prod" ) type ( Config struct { Environment string HTTP HTTPConfig Auth AuthConfig Database string `mapstructure:"database"` Limiter LimiterConfig CacheTTL time.Duration `mapstructure:"ttl"` } AuthConfig struct { ApiKeys map[string]string `mapstructure:"api_keys"` } HTTPConfig struct { Host string `mapstructure:"host"` Port string `mapstructure:"port"` ReadTimeout time.Duration `mapstructure:"readTimeout"` WriteTimeout time.Duration `mapstructure:"writeTimeout"` MaxHeaderMegabytes int `mapstructure:"maxHeaderBytes"` } LimiterConfig struct { RPS int Burst int TTL time.Duration } ) // Init populates Config struct with values from config file // located at filepath and environment variables. func Init(configsDir string) (*Config, error) { populateDefaults() if err := parseConfigFile(configsDir, os.Getenv("APP_ENV")); err != nil { return nil, err } var cfg Config if err := unmarshal(&cfg); err != nil { return nil, err } //setFromEnv(&cfg) return &cfg, nil } func unmarshal(cfg *Config) error { if err := viper.UnmarshalKey("environment", &cfg.Environment); err != nil { return err } if err := viper.UnmarshalKey("cache.ttl", &cfg.CacheTTL); err != nil { return err } if err := viper.UnmarshalKey("http", &cfg.HTTP); err != nil { return err } if err := viper.UnmarshalKey("auth", &cfg.Auth); err != nil { return err } database := viper.GetString("database") configDir := filepath.Dir(viper.ConfigFileUsed()) databaseAbsPath := filepath.Join(configDir, database) viper.Set("database", databaseAbsPath) if err := viper.UnmarshalKey("database", &cfg.Database); err != nil { return err } return viper.UnmarshalKey("limiter", &cfg.Limiter) } func setFromEnv(cfg *Config) { err := envconfig.Process("cvvvvv", &cfg) if err != nil { log.Fatal(err.Error()) } } func parseConfigFile(folder, env string) error { viper.AddConfigPath(folder) viper.SetConfigName("config") if err := viper.ReadInConfig(); err != nil { return err } if env == EnvLocal { return nil } viper.SetConfigName(env) return viper.MergeInConfig() } func populateDefaults() { viper.SetDefault("http.port", defaultHTTPPort) viper.SetDefault("http.max_header_megabytes", defaultHTTPMaxHeaderMegabytes) viper.SetDefault("http.timeouts.read", defaultHTTPRWTimeout) viper.SetDefault("http.timeouts.write", defaultHTTPRWTimeout) viper.SetDefault("auth.accessTokenTTL", defaultAccessTokenTTL) viper.SetDefault("auth.refreshTokenTTL", defaultRefreshTokenTTL) viper.SetDefault("auth.verificationCodeLength", defaultVerificationCodeLength) viper.SetDefault("limiter.rps", defaultLimiterRPS) viper.SetDefault("limiter.burst", defaultLimiterBurst) viper.SetDefault("limiter.ttl", defaultLimiterTTL) }