package config import ( "os" "strconv" "strings" "time" ) type Config struct { HTTPAddr string DBDSN string StoreBackend string RunMigrations bool SNMPEnabled bool SNMPCommunity string ResetDBSecret string // NETTOPO_RESET_DB_SECRET — секрет для POST /api/admin/purge-scans // Пул соединений к PostgreSQL (см. database/sql). По умолчанию ограничен, иначе при большом скане легко исчерпать max_connections на сервере. DBMaxOpenConns int DBMaxIdleConns int DBConnMaxLifetime time.Duration } func FromEnv() Config { addr := os.Getenv("HTTP_ADDR") if addr == "" { addr = ":8080" } dbDSN := os.Getenv("DB_DSN") storeBackend := os.Getenv("STORE_BACKEND") if storeBackend == "" { if dbDSN != "" { storeBackend = "postgres" } else { storeBackend = "memory" } } runMigrations := true if os.Getenv("RUN_MIGRATIONS") == "false" { runMigrations = false } snmpEnabled := true if os.Getenv("SNMP_ENABLED") == "false" { snmpEnabled = false } snmpCommunity := os.Getenv("SNMP_COMMUNITY") if snmpCommunity == "" { snmpCommunity = "public" } maxOpen := intFromEnvMin("DB_MAX_OPEN_CONNS", 25, 1) maxIdle := intFromEnvMin("DB_MAX_IDLE_CONNS", 10, 0) if maxIdle > maxOpen { maxIdle = maxOpen } connLife := 30 * time.Minute if s := strings.TrimSpace(os.Getenv("DB_CONN_MAX_LIFETIME_SEC")); s != "" { if sec, err := strconv.Atoi(s); err == nil { if sec == 0 { connLife = 0 // без ограничения времени жизни соединения } else if sec > 0 { connLife = time.Duration(sec) * time.Second } } } return Config{ HTTPAddr: addr, DBDSN: dbDSN, StoreBackend: storeBackend, RunMigrations: runMigrations, SNMPEnabled: snmpEnabled, SNMPCommunity: snmpCommunity, ResetDBSecret: strings.TrimSpace(os.Getenv("NETTOPO_RESET_DB_SECRET")), DBMaxOpenConns: maxOpen, DBMaxIdleConns: maxIdle, DBConnMaxLifetime: connLife, } } func intFromEnvMin(key string, def, min int) int { s := strings.TrimSpace(os.Getenv(key)) if s == "" { return def } n, err := strconv.Atoi(s) if err != nil || n < min { return def } return n }