package config import ( "errors" "log/slog" "os" "strconv" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" customlogger "github.com/SamuelTariku/FortuneBet-Backend/internal/logger" "github.com/joho/godotenv" ) var ( ErrInvalidDbUrl = errors.New("db url is invalid") ErrInvalidPort = errors.New("port number is invalid") ErrRefreshExpiry = errors.New("refresh token expiry is invalid") ErrAccessExpiry = errors.New("access token expiry is invalid") ErrInvalidJwtKey = errors.New("jwt key is invalid") ErrLogLevel = errors.New("log level not set") ErrInvalidLevel = errors.New("invalid log level") ErrInvalidEnv = errors.New("env not set or invalid") ErrInvalidSMSAPIKey = errors.New("SMS API key is invalid") ErrMissingBetToken = errors.New("missing BET365_TOKEN in .env") ErrInvalidPopOKClientID = errors.New("PopOK client ID is invalid") ErrInvalidPopOKSecretKey = errors.New("PopOK secret key is invalid") ErrInvalidPopOKBaseURL = errors.New("PopOK base URL is invalid") ErrInvalidPopOKCallbackURL = errors.New("PopOK callback URL is invalid") ) type Config struct { Port int DbUrl string RefreshExpiry int AccessExpiry int JwtKey string LogLevel slog.Level Env string AFRO_SMS_API_KEY string AFRO_SMS_SENDER_NAME string AFRO_SMS_RECEIVER_PHONE_NUMBER string ADRO_SMS_HOST_URL string Bet365Token string PopOK domain.PopOKConfig } func NewConfig() (*Config, error) { config := &Config{} if err := config.loadEnv(); err != nil { return nil, err } return config, nil } func (c *Config) loadEnv() error { err := godotenv.Load() if err != nil && !os.IsNotExist(err) { return errors.New("failed to load env file: " + err.Error()) } env := os.Getenv("ENV") if env == "" { return ErrInvalidEnv } c.Env = env portStr := os.Getenv("PORT") if portStr == "" { return ErrInvalidPort } port, err := strconv.Atoi(portStr) if err != nil || port < 1 || port > 65535 { return ErrInvalidPort } c.Port = port dbUrl := os.Getenv("DB_URL") if dbUrl == "" { return ErrInvalidDbUrl } c.DbUrl = dbUrl refreshExpiryStr := os.Getenv("REFRESH_EXPIRY") if refreshExpiryStr == "" { return ErrRefreshExpiry } refreshExpiry, err := strconv.Atoi(refreshExpiryStr) if err != nil || refreshExpiry <= 0 { return ErrRefreshExpiry } c.RefreshExpiry = refreshExpiry jwtKey := os.Getenv("JWT_KEY") if jwtKey == "" { return ErrInvalidJwtKey } c.JwtKey = jwtKey accessExpiryStr := os.Getenv("ACCESS_EXPIRY") if accessExpiryStr == "" { return ErrAccessExpiry } accessExpiry, err := strconv.Atoi(accessExpiryStr) if err != nil || accessExpiry <= 0 { return ErrAccessExpiry } c.AccessExpiry = accessExpiry logLevel := os.Getenv("LOG_LEVEL") if logLevel == "" { return ErrLogLevel } lvl, ok := customlogger.LogLevels[logLevel] if !ok { return ErrInvalidLevel } c.LogLevel = lvl c.AFRO_SMS_API_KEY = os.Getenv("AFRO_SMS_API_KEY") if c.AFRO_SMS_API_KEY == "" { return ErrInvalidSMSAPIKey } c.AFRO_SMS_SENDER_NAME = os.Getenv("AFRO_SMS_SENDER_NAME") if c.AFRO_SMS_SENDER_NAME == "" { c.AFRO_SMS_SENDER_NAME = "FortuneBet" } c.AFRO_SMS_RECEIVER_PHONE_NUMBER = os.Getenv("AFRO_SMS_RECEIVER_PHONE_NUMBER") c.ADRO_SMS_HOST_URL = os.Getenv("ADRO_SMS_HOST_URL") if c.ADRO_SMS_HOST_URL == "" { c.ADRO_SMS_HOST_URL = "https://api.afrosms.com" } popOKClientID := os.Getenv("POPOK_CLIENT_ID") if popOKClientID == "" { return ErrInvalidPopOKClientID } popOKSecretKey := os.Getenv("POPOK_SECRET_KEY") if popOKSecretKey == "" { return ErrInvalidPopOKSecretKey } popOKBaseURL := os.Getenv("POPOK_BASE_URL") if popOKBaseURL == "" { return ErrInvalidPopOKBaseURL } popOKCallbackURL := os.Getenv("POPOK_CALLBACK_URL") if popOKCallbackURL == "" { return ErrInvalidPopOKCallbackURL } c.PopOK = domain.PopOKConfig{ ClientID: popOKClientID, SecretKey: popOKSecretKey, BaseURL: popOKBaseURL, CallbackURL: popOKCallbackURL, } betToken := os.Getenv("BET365_TOKEN") if betToken == "" { return ErrMissingBetToken } c.Bet365Token = betToken return nil }