Files
api-golang/internal/config/config.go
Flavio Fois 4fb3290cf6
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 55s
add rate limiting configuration for authenticated and unauthenticated requests
2026-03-24 08:56:05 +01:00

131 lines
2.7 KiB
Go

package config
import (
"os"
"strconv"
"strings"
"sync"
"time"
)
type RateLimitConfig struct {
UnauthMaxReqs int
UnauthWindow time.Duration
UnauthMaxFails int
UnauthBanDur time.Duration
AuthMaxReqs int
AuthWindow time.Duration
AuthMaxFails int
AuthBanDur time.Duration
}
type Config struct {
Port string
DSN string
Database string
APIKey string
AdminKey string
MaxOpenConns int
MaxIdleConns int
ConnMaxLifetime int
RateLimit RateLimitConfig
}
var (
instance *Config
once sync.Once
)
func Load() *Config {
once.Do(func() { instance = load() })
return instance
}
func load() *Config {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
raw := os.Getenv("API_KEY")
var apiKey string
for _, k := range strings.Split(raw, ",") {
k = strings.TrimSpace(k)
if k != "" {
apiKey = k
break
}
}
raw = os.Getenv("ADMIN_KEY")
var adminKey string
for _, k := range strings.Split(raw, ",") {
k = strings.TrimSpace(k)
if k != "" {
adminKey = k
break
}
}
maxOpenConns, err := strconv.Atoi(os.Getenv("DB_MAX_OPEN_CONNS"))
if err != nil {
maxOpenConns = 30
}
maxIdleConns, err := strconv.Atoi(os.Getenv("DB_MAX_IDLE_CONNS"))
if err != nil {
maxIdleConns = 5
}
connMaxLifetime, err := strconv.Atoi(os.Getenv("DB_CONN_MAX_LIFETIME"))
if err != nil {
connMaxLifetime = 5
}
dbName := os.Getenv("DATABASE_NAME")
if dbName == "" {
panic("DATABASE_NAME environment variable is required")
}
if os.Getenv("DB_DSN") == "" {
panic("DB_DSN environment variable is required")
}
return &Config{
Port: port,
DSN: os.Getenv("DB_DSN"),
Database: dbName,
APIKey: apiKey,
AdminKey: adminKey,
MaxOpenConns: maxOpenConns,
MaxIdleConns: maxIdleConns,
ConnMaxLifetime: connMaxLifetime,
RateLimit: RateLimitConfig{
UnauthMaxReqs: envInt("RL_UNAUTH_MAX_REQS", 10),
UnauthWindow: envDuration("RL_UNAUTH_WINDOW", 5*time.Minute),
UnauthMaxFails: envInt("RL_UNAUTH_MAX_FAILS", 5),
UnauthBanDur: envDuration("RL_UNAUTH_BAN_DUR", 15*time.Minute),
AuthMaxReqs: envInt("RL_AUTH_MAX_REQS", 100),
AuthWindow: envDuration("RL_AUTH_WINDOW", time.Minute),
AuthMaxFails: envInt("RL_AUTH_MAX_FAILS", 20),
AuthBanDur: envDuration("RL_AUTH_BAN_DUR", 5*time.Minute),
},
}
}
func envInt(key string, fallback int) int {
if s := os.Getenv(key); s != "" {
if n, err := strconv.Atoi(s); err == nil {
return n
}
}
return fallback
}
func envDuration(key string, fallback time.Duration) time.Duration {
if s := os.Getenv(key); s != "" {
if d, err := time.ParseDuration(s); err == nil {
return d
}
}
return fallback
}