package config import ( "Yimaru-Backend/internal/domain" customlogger "Yimaru-Backend/internal/logger" "errors" "log/slog" "os" "strconv" "strings" "time" "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") ErrInvalidReportExportPath = errors.New("report export path is 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") // ErrInvalidVeliAPIURL = errors.New("Veli API URL is invalid") // ErrInvalidVeliOperatorKey = errors.New("Veli operator key is invalid") // ErrInvalidVeliSecretKey = errors.New("Veli secret key is invalid") // ErrInvalidAtlasBaseUrl = errors.New("Atlas Base URL is invalid") // ErrInvalidAtlasOperatorID = errors.New("Atlas operator ID is invalid") // ErrInvalidAtlasSecretKey = errors.New("Atlas secret key is invalid") // ErrInvalidAtlasBrandID = errors.New("Atlas brand ID is invalid") // ErrInvalidAtlasPartnerID = errors.New("Atlas Partner ID is invalid") ErrMissingResendApiKey = errors.New("missing Resend Api key") ErrMissingResendSenderEmail = errors.New("missing Resend sender name") ErrMissingTwilioAccountSid = errors.New("missing twilio account sid") ErrMissingTwilioAuthToken = errors.New("missing twilio auth token") ErrMissingTwilioSenderPhoneNumber = errors.New("missing twilio sender phone number") ) // type EnetPulseConfig struct { // UserName string `mapstructure:"username"` // Token string `mapstructure:"token"` // ProviderID string `mapstructure:"provider_id"` // } // type AleaPlayConfig struct { // Enabled bool `mapstructure:"enabled"` // BaseURL string `mapstructure:"base_url"` // "https://api.aleaplay.com" // OperatorID string `mapstructure:"operator_id"` // Your operator ID with Alea // SecretKey string `mapstructure:"secret_key"` // API secret for signatures // GameListURL string `mapstructure:"game_list_url"` // Endpoint to fetch available games // DefaultCurrency string `mapstructure:"default_currency"` // "USD", "EUR", etc. // SessionTimeout int `mapstructure:"session_timeout"` // In hours // } // type VeliConfig struct { // APIKey string `mapstructure:"VELI_API_KEY"` // BaseURL string `mapstructure:"VELI_BASE_URL"` // SecretKey string `mapstructure:"VELI_SECRET_KEY"` // OperatorID string `mapstructure:"VELI_OPERATOR_ID"` // BrandID string `mapstructure:"VELI_BRAND_ID"` // Currency string `mapstructure:"VELI_DEFAULT_CURRENCY"` // WebhookURL string `mapstructure:"VELI_WEBHOOK_URL"` // Enabled bool `mapstructure:"Enabled"` // } type AFROSMSConfig struct { AfroSMSSenderName string `mapstructure:"afrom_sms_sender_name"` AfroSMSIdentifierID string `mapstructure:"afro_sms_identifier_id"` AfroSMSAPIKey string `mapstructure:"afro_sms_api_key"` AfroSMSBaseURL string `mapstructure:"afro_sms_base_url"` } // type AtlasConfig struct { // BaseURL string `mapstructure:"ATLAS_BASE_URL"` // SecretKey string `mapstructure:"ATLAS_SECRET_KEY"` // OperatorID string `mapstructure:"ATLAS_OPERATOR_ID"` // CasinoID string `mapstructure:"ATLAS_BRAND_ID"` // PartnerID string `mapstructure:"ATLAS_PARTNER_ID"` // } type ARIFPAYConfig struct { APIKey string `mapstructure:"ARIFPAY_API_KEY"` BaseURL string `mapstructure:"ARIFPAY_BASE_URL"` // Default URLs CancelUrl string `mapstructure:"cancelUrl"` SuccessUrl string `mapstructure:"successUrl"` ErrorUrl string `mapstructure:"errorUrl"` B2CNotifyUrl string `mapstructure:"notifyUrl"` C2BNotifyUrl string `mapstructure:"notifyUrl"` // Default Payment Configs PaymentMethods []string `mapstructure:"paymentMethods"` ExpireDate string `mapstructure:"expireDate"` ItemName string `mapstructure:"name"` Quantity int `mapstructure:"quantity"` Description string `mapstructure:"description"` BeneficiaryAccountNumber string `mapstructure:"accountNumber"` Bank string `mapstructure:"bank"` Lang string `mapstructure:"amount"` } type SANTIMPAYConfig struct { SecretKey string `mapstructure:"secret_key"` MerchantID string `mapstructure:"merchantId"` BaseURL string `mapstructure:"base_url"` NotifyURL string `mapstructure:"notifyUrl"` CancelUrl string `mapstructure:"cancelUrl"` SuccessUrl string `mapstructure:"successUrl"` } type TELEBIRRConfig struct { TelebirrFabricAppID string `mapstructure:"fabric_app_id"` TelebirrAppSecret string `mapstructure:"appSecret"` TelebirrBaseURL string `mapstructure:"base_url"` TelebirrMerchantCode string `mapstructure:"merchant_code"` TelebirrCallbackURL string `mapstructure:"callback_url"` } type Config struct { AFROSMSConfig AFROSMSConfig `mapstructure:"afro_sms_config"` APP_VERSION string FIXER_API_KEY string FIXER_BASE_URL string BASE_CURRENCY domain.IntCurrency Port int Service string DbUrl string RefreshExpiry int AccessExpiry int JwtKey string LogLevel slog.Level Env string ReportExportPath string `mapstructure:"REPORT_EXPORT_PATH"` AFRO_SMS_API_KEY string AFRO_SMS_SENDER_NAME string AFRO_SMS_RECEIVER_PHONE_NUMBER string ADRO_SMS_HOST_URL string CHAPA_WEBHOOK_SECRET string CHAPA_TRANSFER_TYPE string CHAPA_PAYMENT_TYPE string CHAPA_SECRET_KEY string CHAPA_PUBLIC_KEY string CHAPA_BASE_URL string CHAPA_ENCRYPTION_KEY string CHAPA_CALLBACK_URL string CHAPA_RETURN_URL string CHAPA_RECEIPT_URL string ARIFPAY ARIFPAYConfig `mapstructure:"arifpay_config"` SANTIMPAY SANTIMPAYConfig `mapstructure:"santimpay_config"` TELEBIRR TELEBIRRConfig `mapstructure:"telebirr_config"` ResendApiKey string ResendSenderEmail string TwilioAccountSid string TwilioAuthToken string TwilioSenderPhoneNumber string RedisAddr string KafkaBrokers []string } 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 c.APP_VERSION = os.Getenv("APP_VERSION") c.ReportExportPath = os.Getenv("REPORT_EXPORT_PATH") if c.ReportExportPath == "" { return ErrInvalidReportExportPath } c.RedisAddr = os.Getenv("REDIS_ADDR") c.KafkaBrokers = strings.Split(os.Getenv("KAFKA_BROKERS"), ",") c.CHAPA_TRANSFER_TYPE = os.Getenv("CHAPA_TRANSFER_TYPE") c.CHAPA_PAYMENT_TYPE = os.Getenv("CHAPA_PAYMENT_TYPE") c.FIXER_API_KEY = os.Getenv("FIXER_API_KEY") c.BASE_CURRENCY = domain.IntCurrency(os.Getenv("BASE_CURRENCY")) c.FIXER_BASE_URL = os.Getenv("FIXER_BASE_URL") 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 } //Afro SMS c.AFROSMSConfig.AfroSMSAPIKey = os.Getenv("AFRO_SMS_API_KEY") c.AFROSMSConfig.AfroSMSIdentifierID = os.Getenv("AFRO_SMS_IDENTIFIER_ID") c.AFROSMSConfig.AfroSMSBaseURL = os.Getenv("AFRO_SMS_BASE_URL") c.AFROSMSConfig.AfroSMSSenderName = os.Getenv("AFRO_SMS_SENDER_NAME") //Telebirr c.TELEBIRR.TelebirrBaseURL = os.Getenv("TELEBIRR_BASE_URL") c.TELEBIRR.TelebirrAppSecret = os.Getenv("TELEBIRR_APP_SECRET") c.TELEBIRR.TelebirrAppSecret = os.Getenv("TELEBIRR_FABRIC_APP_ID") c.TELEBIRR.TelebirrMerchantCode = os.Getenv("TELEBIRR_MERCHANT_CODE") c.TELEBIRR.TelebirrCallbackURL = os.Getenv("TELEBIRR_CALLBACK_URL") //Chapa c.CHAPA_WEBHOOK_SECRET = os.Getenv("CHAPA_WEBHOOK_SECRET") c.CHAPA_SECRET_KEY = os.Getenv("CHAPA_SECRET_KEY") c.CHAPA_PUBLIC_KEY = os.Getenv("CHAPA_PUBLIC_KEY") c.CHAPA_ENCRYPTION_KEY = os.Getenv("CHAPA_ENCRYPTION_KEY") c.CHAPA_BASE_URL = os.Getenv("CHAPA_BASE_URL") c.CHAPA_RECEIPT_URL = os.Getenv("CHAPA_RECEIPT_URL") if c.CHAPA_BASE_URL == "" { c.CHAPA_BASE_URL = "https://api.chapa.co/v1" } c.CHAPA_CALLBACK_URL = os.Getenv("CHAPA_CALLBACK_URL") c.CHAPA_RETURN_URL = os.Getenv("CHAPA_RETURN_URL") c.ARIFPAY.APIKey = os.Getenv("ARIFPAY_API_KEY") c.ARIFPAY.CancelUrl = os.Getenv("ARIFPAY_CANCEL_URL") c.ARIFPAY.ErrorUrl = os.Getenv("ARIFPAY_ERROR_URL") c.ARIFPAY.C2BNotifyUrl = os.Getenv("ARIFPAY_C2B_NOTIFY_URL") c.ARIFPAY.B2CNotifyUrl = os.Getenv("ARIFPAY_B2C_NOTIFY_URL") c.ARIFPAY.SuccessUrl = os.Getenv("ARIFPAY_SUCCESS_URL") c.ARIFPAY.BaseURL = os.Getenv("ARIFPAY_BASE_URL") c.ARIFPAY.Bank = os.Getenv("ARIFPAY_BANK") c.ARIFPAY.BeneficiaryAccountNumber = os.Getenv("ARIFPAY_BENEFICIARY_ACCOUNT_NUMBER") c.ARIFPAY.Description = os.Getenv("ARIFPAY_DESCRIPTION") c.ARIFPAY.ExpireDate = time.Now().Add(time.Hour * 3).Format("2006-01-02") c.ARIFPAY.ItemName = os.Getenv("ARIFPAY_ITEM_NAME") c.ARIFPAY.Lang = "EN" c.ARIFPAY.Quantity = 1 c.ARIFPAY.PaymentMethods = []string{"TELEBIRR", "AWAASH", "AWAASH_WALLET", "PSS", "CBE", "AMOLE", "BOA", "KACHA", "TELEBIRR", "HELLOCASH", "MPESSA"} c.SANTIMPAY.SecretKey = os.Getenv("SANTIMPAY_SECRET_KEY") c.SANTIMPAY.MerchantID = os.Getenv("SANTIMPAY_MERCHANT_ID") c.SANTIMPAY.BaseURL = os.Getenv("SANTIMPAY_BASE_URL") c.SANTIMPAY.NotifyURL = os.Getenv("SANTIMPAY_NOTIFY_URL") c.SANTIMPAY.CancelUrl = os.Getenv("SANTIMPAY_CANCEL_URL") // //Alea Play // aleaEnabled := os.Getenv("ALEA_ENABLED") // if aleaEnabled == "" { // aleaEnabled = "false" // Default disabled // } // if enabled, err := strconv.ParseBool(aleaEnabled); err != nil { // return fmt.Errorf("invalid ALEA_ENABLED value: %w", err) // } else { // c.AleaPlay.Enabled = enabled // } // c.AleaPlay.BaseURL = os.Getenv("ALEA_BASE_URL") // if c.AleaPlay.BaseURL == "" && c.AleaPlay.Enabled { // return errors.New("ALEA_BASE_URL is required when Alea is enabled") // } // c.AleaPlay.OperatorID = os.Getenv("ALEA_OPERATOR_ID") // if c.AleaPlay.OperatorID == "" && c.AleaPlay.Enabled { // return errors.New("ALEA_OPERATOR_ID is required when Alea is enabled") // } // c.AleaPlay.SecretKey = os.Getenv("ALEA_SECRET_KEY") // if c.AleaPlay.SecretKey == "" && c.AleaPlay.Enabled { // return errors.New("ALEA_SECRET_KEY is required when Alea is enabled") // } // c.AleaPlay.GameListURL = os.Getenv("ALEA_GAME_LIST_URL") // c.AleaPlay.DefaultCurrency = os.Getenv("ALEA_DEFAULT_CURRENCY") // if c.AleaPlay.DefaultCurrency == "" { // c.AleaPlay.DefaultCurrency = "USD" // } // sessionTimeoutStr := os.Getenv("ALEA_SESSION_TIMEOUT") // if sessionTimeoutStr != "" { // timeout, err := strconv.Atoi(sessionTimeoutStr) // if err == nil { // c.AleaPlay.SessionTimeout = timeout // } // } // //Veli Games // veliEnabled := os.Getenv("VELI_ENABLED") // if veliEnabled == "" { // veliEnabled = "true" // Default to disabled if not specified // } // veliOperatorID := os.Getenv("VELI_OPERATOR_ID") // veliBrandID := os.Getenv("VELI_BRAND_ID") // c.VeliGames.OperatorID = os.Getenv("VELI_OPERATOR_ID") // c.VeliGames.BrandID = os.Getenv("VELI_BRAND_ID") // if enabled, err := strconv.ParseBool(veliEnabled); err != nil { // return fmt.Errorf("invalid VELI_ENABLED value: %w", err) // } else { // c.VeliGames.Enabled = enabled // } // // apiURL := os.Getenv("VELI_BASE_URL") // // if apiURL == "" { // // apiURL = "https://api.velitech.games" // Default production URL // // } // c.VeliGames.BaseURL = os.Getenv("VELI_BASE_URL") // operatorKey := os.Getenv("VELI_OPERATOR_KEY") // if operatorKey == "" && c.VeliGames.Enabled { // return ErrInvalidVeliOperatorKey // } // c.VeliGames.OperatorKey = operatorKey // secretKey := os.Getenv("VELI_SECRET_KEY") // if secretKey == "" && c.VeliGames.Enabled { // return ErrInvalidVeliSecretKey // } // c.VeliGames.SecretKey = secretKey // // c.VeliGames.GameIDs.Aviator = os.Getenv("VELI_GAME_ID_AVIATOR") // defaultCurrency := os.Getenv("VELI_DEFAULT_CURRENCY") // if defaultCurrency == "" { // defaultCurrency = "USD" // Default currency // } // c.VeliGames.DefaultCurrency = defaultCurrency 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 = "Yimaru" } 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.afromessage.com" } //Atlas // c.Atlas.BaseURL = os.Getenv("ATLAS_BASE_URL") // c.Atlas.CasinoID = os.Getenv("ATLAS_CASINO_ID") // c.Atlas.OperatorID = os.Getenv("ATLAS_OPERATOR_ID") // c.Atlas.PartnerID = os.Getenv("ATLAS_PARTNER_ID") // c.Atlas.SecretKey = os.Getenv("ATLAS_SECRET_KEY") // popOKClientID := os.Getenv("POPOK_CLIENT_ID") // // popOKPlatform := os.Getenv("POPOK_PLATFORM") // 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, // Platform: popOKPlatform, // } // AtlasBaseUrl := os.Getenv("ATLAS_BASE_URL") // if AtlasBaseUrl == "" { // return ErrInvalidAtlasBaseUrl // } // AtlasSecretKey := os.Getenv("ATLAS_SECRET_KEY") // if AtlasSecretKey == "" { // return ErrInvalidAtlasSecretKey // } // AtlasBrandID := os.Getenv("ATLAS_BRAND_ID") // if AtlasBrandID == "" { // return ErrInvalidAtlasBrandID // } // AtlasPartnerID := os.Getenv("ATLAS_PARTNER_ID") // if AtlasPartnerID == "" { // return ErrInvalidAtlasPartnerID // } // AtlasOperatorID := os.Getenv("ATLAS_OPERATOR_ID") // if AtlasOperatorID == "" { // return ErrInvalidAtlasOperatorID // } // c.Atlas = AtlasConfig{ // BaseURL: AtlasBaseUrl, // SecretKey: AtlasSecretKey, // CasinoID: AtlasBrandID, // PartnerID: AtlasPartnerID, // OperatorID: AtlasOperatorID, // } // betToken := os.Getenv("BET365_TOKEN") // if betToken == "" { // return ErrMissingBetToken // } // c.Bet365Token = betToken resendApiKey := os.Getenv("RESEND_API_KEY") if resendApiKey == "" { return ErrMissingResendApiKey } c.ResendApiKey = resendApiKey resendSenderEmail := os.Getenv("RESEND_SENDER_EMAIL") if resendSenderEmail == "" { return ErrMissingResendSenderEmail } c.ResendSenderEmail = resendSenderEmail twilioAccountSid := os.Getenv("TWILIO_ACCOUNT_SID") if twilioAccountSid == "" { return ErrMissingTwilioAccountSid } c.TwilioAccountSid = twilioAccountSid twilioAuthToken := os.Getenv("TWILIO_AUTH_TOKEN") if twilioAuthToken == "" { return ErrMissingTwilioAuthToken } c.TwilioAuthToken = twilioAuthToken twilioSenderPhoneNumber := os.Getenv("TWILIO_SENDER_PHONE_NUMBER") if twilioSenderPhoneNumber == "" { return ErrMissingTwilioSenderPhoneNumber } c.TwilioSenderPhoneNumber = twilioSenderPhoneNumber return nil } type ChapaConfig struct { ChapaPaymentType string `mapstructure:"chapa_payment_type"` ChapaTransferType string `mapstructure:"chapa_transfer_type"` }