All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 55s
131 lines
2.7 KiB
Go
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
|
|
}
|