Files
RenewCMS/internal/infrastructure/config/databaseSettings.go
T

123 lines
3.5 KiB
Go

package config
import (
"fmt"
"os"
"slices"
"strconv"
"strings"
"time"
)
const (
DatabaseDriverSQLite = "sqlite"
DatabaseDriverMySQL = "mysql"
DefaultDatabaseDriver = DatabaseDriverSQLite
DefaultDatabasePort = "3306"
DefaultDatabaseTLS = "false"
DefaultMaxOpenConns = "10"
DefaultMaxIdleConns = "5"
DefaultConnMaxLifetimeSeconds = "300"
EnvDatabaseDriver = "DB_DRIVER"
envDatabaseHost = "DB_HOST"
envDatabasePort = "DB_PORT"
envDatabaseUser = "DB_USER"
envDatabasePassword = "DB_PASSWORD"
envDatabaseName = "DB_NAME"
envDatabaseTLS = "DB_TLS"
envDatabaseMaxOpenConns = "DB_MAX_OPEN_CONNS"
envDatabaseMaxIdleConns = "DB_MAX_IDLE_CONNS"
envDatabaseConnMaxLifetimeSecs = "DB_CONN_MAX_LIFETIME_SECONDS"
)
var mysqlRequiredEnvVars = []string{envDatabaseHost, envDatabaseUser, envDatabasePassword, envDatabaseName}
var DatabaseTLSModes = []string{"false", "true", "skip-verify", "preferred"}
type DatabaseSettings struct {
Driver string
Host string
Port string
User string
Password string
Name string
TLS string
MaxOpenConns int
MaxIdleConns int
ConnMaxLifetime time.Duration
}
func DatabaseRequiredEnvVars(driver string) []string {
if driver == DatabaseDriverMySQL {
return slices.Clone(mysqlRequiredEnvVars)
}
return nil
}
func MissingEnvVarError(names []string, lookup func(string) (string, bool)) error {
for _, name := range names {
if _, isSet := lookup(name); !isSet {
return fmt.Errorf("Environment variable %s is not set", name)
}
}
return nil
}
func databaseDriverFromEnv() string {
return envOrDefault(EnvDatabaseDriver, DefaultDatabaseDriver)
}
func databaseSettingsFromEnv() (DatabaseSettings, error) {
driver := databaseDriverFromEnv()
if driver != DatabaseDriverMySQL {
return DatabaseSettings{Driver: driver}, nil
}
tls := envOrDefault(envDatabaseTLS, DefaultDatabaseTLS)
if !slices.Contains(DatabaseTLSModes, tls) {
return DatabaseSettings{}, fmt.Errorf("%s must be one of %s, got %q", envDatabaseTLS, strings.Join(DatabaseTLSModes, ", "), tls)
}
maxOpen, err := nonNegativeIntEnv(envDatabaseMaxOpenConns, DefaultMaxOpenConns)
if err != nil {
return DatabaseSettings{}, err
}
maxIdle, err := nonNegativeIntEnv(envDatabaseMaxIdleConns, DefaultMaxIdleConns)
if err != nil {
return DatabaseSettings{}, err
}
lifetimeSeconds, err := nonNegativeIntEnv(envDatabaseConnMaxLifetimeSecs, DefaultConnMaxLifetimeSeconds)
if err != nil {
return DatabaseSettings{}, err
}
return DatabaseSettings{
Driver: driver,
Host: os.Getenv(envDatabaseHost),
Port: envOrDefault(envDatabasePort, DefaultDatabasePort),
User: os.Getenv(envDatabaseUser),
Password: os.Getenv(envDatabasePassword),
Name: os.Getenv(envDatabaseName),
TLS: tls,
MaxOpenConns: maxOpen,
MaxIdleConns: maxIdle,
ConnMaxLifetime: time.Duration(lifetimeSeconds) * time.Second,
}, nil
}
func envOrDefault(name string, fallback string) string {
if value := os.Getenv(name); value != "" {
return value
}
return fallback
}
func nonNegativeIntEnv(name string, fallback string) (int, error) {
raw := envOrDefault(name, fallback)
value, err := strconv.Atoi(raw)
if err != nil || value < 0 {
return 0, fmt.Errorf("%s must be a non-negative whole number, got %q", name, raw)
}
return value, nil
}