210 lines
6.0 KiB
Go
210 lines
6.0 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/joho/godotenv"
|
|
)
|
|
|
|
type Config struct {
|
|
Server ServerConfig
|
|
Database DatabaseConfig
|
|
JWT JWTConfig
|
|
Redis RedisConfig
|
|
NATS NATSConfig
|
|
Storage StorageConfig
|
|
}
|
|
|
|
// ServerConfig type holds the information about the http server settings
|
|
type ServerConfig struct {
|
|
Port string // HTTP port to listen on
|
|
Environment string // can be development, staging, production
|
|
ReadTimeout time.Duration // Max time to read request
|
|
WriteTimeout time.Duration // Max time to write response
|
|
}
|
|
|
|
// DatabaseConfig contains postgresSQL connection settings
|
|
type DatabaseConfig struct {
|
|
Host string // Database host
|
|
Port string // Database port
|
|
User string // Database user
|
|
Password string // Database password
|
|
DBName string // Database name
|
|
SSLMode string // SSL mode : disable, require, verify-full ? not sure what this field is set for
|
|
MaxOpenConns int // Maximum open connections
|
|
MaxIdleConns int // Maximum idle connections
|
|
ConnMaxLifetime time.Duration // Maximum connection lifetime
|
|
}
|
|
|
|
// JWT Config contains JWT token settings
|
|
type JWTConfig struct {
|
|
AccessSecret string // Secret for access tokens
|
|
RefreshSecret string // Secret for refresh tokens
|
|
AccessExpiry time.Duration // Accees token expiry (15 minutes)
|
|
RefreshExpiry time.Duration // Refresh token expiry (7 days)
|
|
Issuer string // Token issuer claim
|
|
}
|
|
|
|
type RedisConfig struct {
|
|
Host string // Redis host
|
|
Port string // Redis port
|
|
Password string // Redis password (set to empty if no auth is set)
|
|
DB int // Redis database number
|
|
}
|
|
|
|
// NATSConfig contains NATS messaging settings
|
|
type NATSConfig struct {
|
|
URL string // NATS server URL
|
|
}
|
|
|
|
// StorageCongfig contains MinIO (s3) settings
|
|
type StorageConfig struct {
|
|
Endpoint string // MinIO endpoint
|
|
AccessKeyID string // Access key
|
|
SecretAccessKey string // Secret key
|
|
BucketName string // Bucket name
|
|
UseSSL bool // User HTTPS
|
|
}
|
|
|
|
func Load() (*Config, error) {
|
|
if os.Getenv("APP_ENV") != "production" {
|
|
if err := godotenv.Load(); err != nil {
|
|
fmt.Println("Warning: .env file not found, using environment variables")
|
|
}
|
|
}
|
|
|
|
cfg := &Config{
|
|
Server: ServerConfig{
|
|
Port: getEnv("SERVER_PORT", "8080"),
|
|
Environment: getEnv("APP_ENV", "development"),
|
|
ReadTimeout: parseDuration(getEnv("SERVER_READ_TIMEOUT", "10s")),
|
|
WriteTimeout: parseDuration(getEnv("SERVER_WRITE_TIMEOUT", "10s")),
|
|
},
|
|
Database: DatabaseConfig{
|
|
Host: getEnv("DB_HOST", "localhost"),
|
|
Port: getEnv("DB_PORT", "5432"),
|
|
User: getEnv("DB_USER", "aurganize"),
|
|
Password: getEnv("DB_PASSWORD", ""),
|
|
DBName: getEnv("DB_NAME", "aruganize_db_1"),
|
|
SSLMode: getEnv("DB_SSLMODE", "disable"),
|
|
MaxOpenConns: parseInt(getEnv("DB_MAX_OPEN_CONNECTIONS", "25")),
|
|
MaxIdleConns: parseInt(getEnv("DB_MAX_IDLE_CONNECTIONS", "5")),
|
|
ConnMaxLifetime: parseDuration(getEnv("DB_CONNECTION_MAX_LIFETIME", "5m")),
|
|
},
|
|
|
|
JWT: JWTConfig{
|
|
AccessSecret: getEnv("JWT_ACCESS_SECRET", ""),
|
|
RefreshSecret: getEnv("JWT_REFRESH_SECRET", ""),
|
|
AccessExpiry: parseDuration(getEnv("JWT_ACCESS_EXPIRY", "15m")),
|
|
RefreshExpiry: parseDuration(getEnv("JWT_REFRESH_EXPIRY", "168h")),
|
|
Issuer: getEnv("JWT_ISSUER", "aurganize-v62"),
|
|
},
|
|
Redis: RedisConfig{
|
|
Host: getEnv("REDIST_HOST", "localhost"),
|
|
Port: getEnv("REDIS_PORT", "6379"),
|
|
Password: getEnv("REDIS_PASSWORD", ""),
|
|
DB: parseInt(getEnv("REDIS_DB", "0")),
|
|
},
|
|
NATS: NATSConfig{
|
|
URL: getEnv("NATS_URL", "nats://localhost:4222"),
|
|
},
|
|
Storage: StorageConfig{
|
|
Endpoint: getEnv("MINIO_ENDPOINT", "localhost:9000"),
|
|
AccessKeyID: getEnv("MINIO_ACCESS_KEY", "minioadmin"),
|
|
SecretAccessKey: getEnv("MINIO_SECRET_KEY", "miniosecretkey"),
|
|
BucketName: getEnv("MINIO_BUCKET", "aurganize_bucket_1"),
|
|
UseSSL: parseBool(getEnv("MINIO_USE_SSL", "false")),
|
|
},
|
|
}
|
|
if err := cfg.Validate(); err != nil {
|
|
return nil, fmt.Errorf("configuration validation failure [%w]", err)
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
// Validate checks if all required configuration is present and valid
|
|
func (c *Config) Validate() error {
|
|
// Database password required in production
|
|
if c.Database.Password == "" && c.Server.Environment == "production" {
|
|
return fmt.Errorf("DB_PASSWORD is required in production")
|
|
}
|
|
// JWT secrets are required always
|
|
if c.JWT.AccessSecret == "" {
|
|
return fmt.Errorf("JWT_ACCESS_SECRET is required")
|
|
}
|
|
|
|
if c.JWT.RefreshSecret == "" {
|
|
return fmt.Errorf("JWT_REFRESH_SECRET is required")
|
|
}
|
|
// JWT secrets should be different
|
|
if c.JWT.AccessSecret == c.JWT.RefreshSecret {
|
|
return fmt.Errorf("JWT_ACCESS_SECRET and JWT_REFRESH_SECRET must be different")
|
|
}
|
|
|
|
validEnvs := map[string]bool{
|
|
"development": true,
|
|
"test": true,
|
|
"staging": true,
|
|
"UAT": true,
|
|
"production": true,
|
|
}
|
|
if !validEnvs[c.Server.Environment] {
|
|
return fmt.Errorf("invalid environment configured in enviroment")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Helper Functions
|
|
func getEnv(key, defaultValue string) string {
|
|
if value := os.Getenv(key); value != "" {
|
|
return value
|
|
}
|
|
return defaultValue
|
|
}
|
|
|
|
func parseDuration(s string) time.Duration {
|
|
d, err := time.ParseDuration(s)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return d
|
|
}
|
|
|
|
func parseInt(s string) int {
|
|
i, err := strconv.Atoi(s)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return i
|
|
}
|
|
|
|
func parseBool(s string) bool {
|
|
b, err := strconv.ParseBool(s)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return b
|
|
}
|
|
|
|
// DatabaseDSN returns the PostgreSQL connection string
|
|
func (c *Config) DatabaseDSN() string {
|
|
return fmt.Sprintf(
|
|
"host=%s post %s user=%s password=%s dbname=%s sslmode=%s",
|
|
c.Database.Host,
|
|
c.Database.Port,
|
|
c.Database.User,
|
|
c.Database.Password,
|
|
c.Database.DBName,
|
|
c.Database.SSLMode,
|
|
)
|
|
}
|
|
|
|
// RedisDSN returns the Redis connection string
|
|
func (c *Config) RedisDSN() string {
|
|
return fmt.Sprintf("%s:%s", c.Redis.Host, c.Redis.Port)
|
|
}
|