@@ -0,0 +1,99 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gardomatic.kleiax.de/internal/api"
|
||||
"gardomatic.kleiax.de/internal/mailer"
|
||||
"gardomatic.kleiax.de/internal/platform/environment"
|
||||
)
|
||||
|
||||
func configFromEnvironment() (api.Config, error) {
|
||||
var errs []error
|
||||
required := func(name string) string {
|
||||
value, err := environment.Required(name)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return value
|
||||
}
|
||||
integer := func(name string, fallback int) int {
|
||||
value, err := environment.Int(name, fallback)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return value
|
||||
}
|
||||
boolean := func(name string, fallback bool) bool {
|
||||
value, err := environment.Bool(name, fallback)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return value
|
||||
}
|
||||
duration := func(name string, fallback time.Duration) time.Duration {
|
||||
value, err := environment.Duration(name, fallback)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return value
|
||||
}
|
||||
floating := func(name string, fallback float64) float64 {
|
||||
value, err := environment.Float(name, fallback)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
cfg := api.Config{
|
||||
Host: environment.String("GARDOMATIC_API_HOST", ""),
|
||||
Port: integer("GARDOMATIC_API_PORT", 4000),
|
||||
Env: environment.String("GARDOMATIC_ENV", "development"),
|
||||
WebBaseURL: environment.String("GARDOMATIC_WEB_BASE_URL", "http://localhost:4040"),
|
||||
DB: api.DatabaseConfig{
|
||||
Dsn: required("GARDOMATIC_DB_DSN"), MaxOpenConns: integer("GARDOMATIC_DB_MAX_OPEN_CONNS", 25),
|
||||
MaxIdleConns: integer("GARDOMATIC_DB_MAX_IDLE_CONNS", 25), MaxIdleTime: duration("GARDOMATIC_DB_MAX_IDLE_TIME", 15*time.Minute),
|
||||
},
|
||||
Limiter: api.LimiterConfig{Enabled: boolean("GARDOMATIC_RATE_LIMIT_ENABLED", true), Rps: floating("GARDOMATIC_RATE_LIMIT_RPS", 10), Burst: integer("GARDOMATIC_RATE_LIMIT_BURST", 40)},
|
||||
Session: api.SessionConfig{Lifetime: duration("GARDOMATIC_SESSION_LIFETIME", 12*time.Hour), IdleTimeout: duration("GARDOMATIC_SESSION_IDLE_TIMEOUT", 30*time.Minute), CookieName: environment.String("GARDOMATIC_SESSION_COOKIE_NAME", "gardomatic_session"), CookieSecure: boolean("GARDOMATIC_COOKIE_SECURE", false)},
|
||||
Mail: mailer.Config{Mode: mailer.Mode(environment.String("GARDOMATIC_SMTP_MODE", string(mailer.ModeFile))), Host: environment.String("GARDOMATIC_SMTP_HOST", ""), Port: integer("GARDOMATIC_SMTP_PORT", 25), Username: environment.String("GARDOMATIC_SMTP_USERNAME", ""), Password: environment.String("GARDOMATIC_SMTP_PASSWORD", ""), Sender: environment.String("GARDOMATIC_SMTP_SENDER", "gardomatic@localhost"), FilePath: environment.String("GARDOMATIC_SMTP_FILE_PATH", "/tmp/gardomatic-mails.log")},
|
||||
Cors: api.CORSConfig{TrustedOrigins: environment.CSV("GARDOMATIC_CORS_TRUSTED_ORIGINS")},
|
||||
}
|
||||
|
||||
if cfg.Port < 1 || cfg.Port > 65535 {
|
||||
errs = append(errs, errors.New("GARDOMATIC_API_PORT must be between 1 and 65535"))
|
||||
}
|
||||
if cfg.Env != "development" && cfg.Env != "test" && cfg.Env != "production" {
|
||||
errs = append(errs, fmt.Errorf("GARDOMATIC_ENV has unsupported value %q", cfg.Env))
|
||||
}
|
||||
if cfg.DB.MaxOpenConns < 1 || cfg.DB.MaxIdleConns < 0 || cfg.DB.MaxIdleConns > cfg.DB.MaxOpenConns {
|
||||
errs = append(errs, errors.New("database pool limits are invalid"))
|
||||
}
|
||||
if cfg.Limiter.Rps <= 0 || cfg.Limiter.Burst < 1 {
|
||||
errs = append(errs, errors.New("rate limit values must be positive"))
|
||||
}
|
||||
if strings.TrimSpace(cfg.Session.CookieName) == "" {
|
||||
errs = append(errs, errors.New("GARDOMATIC_SESSION_COOKIE_NAME must not be empty"))
|
||||
}
|
||||
for _, origin := range cfg.Cors.TrustedOrigins {
|
||||
parsed, err := url.ParseRequestURI(origin)
|
||||
if err != nil || parsed.Scheme == "" || parsed.Host == "" {
|
||||
errs = append(errs, fmt.Errorf("invalid trusted origin %q", origin))
|
||||
}
|
||||
}
|
||||
if parsed, err := url.ParseRequestURI(cfg.WebBaseURL); err != nil || parsed.Scheme == "" || parsed.Host == "" {
|
||||
errs = append(errs, errors.New("GARDOMATIC_WEB_BASE_URL must be an absolute URL"))
|
||||
}
|
||||
if cfg.Env == "production" && !cfg.Session.CookieSecure {
|
||||
errs = append(errs, errors.New("GARDOMATIC_COOKIE_SECURE must be true in production"))
|
||||
}
|
||||
if _, err := mailer.New(cfg.Mail); err != nil {
|
||||
errs = append(errs, fmt.Errorf("mail configuration: %w", err))
|
||||
}
|
||||
return cfg, errors.Join(errs...)
|
||||
}
|
||||
Reference in New Issue
Block a user