Files
backend/internal/config/config.go
2025-12-13 22:34:01 +05:00

140 lines
3.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package config
import (
"context"
"fmt"
"os"
"strconv"
"time"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/joho/godotenv"
)
// Config содержит конфигурацию приложения
type Config struct {
// Database
DatabaseURL string
// Server
ServerHost string
ServerPort string
AppEnv string
// JWT
JWTSecret string
JWTAccessTokenTTL time.Duration
JWTRefreshTokenTTL time.Duration
// CORS
CORSAllowedOrigins []string
CORSAllowedMethods []string
CORSAllowedHeaders []string
// Rate Limiting
RateLimitRequestsPerMinute int
RateLimitBurst int
// Matching Algorithm
MatchingDefaultRadiusMeters int
MatchingDefaultLimit int
}
// Load загружает конфигурацию из переменных окружения
func Load() (*Config, error) {
// Загружаем .env файл если он существует
_ = godotenv.Load()
cfg := &Config{
DatabaseURL: getDatabaseURL(),
ServerHost: getEnv("APP_HOST", "0.0.0.0"),
ServerPort: getEnv("APP_PORT", "8080"),
AppEnv: getEnv("APP_ENV", "development"),
JWTSecret: getEnv("JWT_SECRET", "change_me_to_secure_random_string_min_32_chars"),
JWTAccessTokenTTL: parseDuration(getEnv("JWT_ACCESS_TOKEN_EXPIRY", "15m")),
JWTRefreshTokenTTL: parseDuration(getEnv("JWT_REFRESH_TOKEN_EXPIRY", "168h")), // 7 days
RateLimitRequestsPerMinute: getEnvInt("RATE_LIMIT_REQUESTS_PER_MINUTE", 60),
RateLimitBurst: getEnvInt("RATE_LIMIT_BURST", 10),
MatchingDefaultRadiusMeters: getEnvInt("MATCHING_DEFAULT_RADIUS_METERS", 10000),
MatchingDefaultLimit: getEnvInt("MATCHING_DEFAULT_LIMIT", 20),
}
return cfg, nil
}
// NewDBPool создает новый пул соединений с БД
func NewDBPool(ctx context.Context, databaseURL string) (*pgxpool.Pool, error) {
config, err := pgxpool.ParseConfig(databaseURL)
if err != nil {
return nil, fmt.Errorf("failed to parse database URL: %w", err)
}
// Настройка пула соединений
config.MaxConns = 25
config.MinConns = 5
config.MaxConnLifetime = time.Hour
config.MaxConnIdleTime = time.Minute * 30
config.HealthCheckPeriod = time.Minute
pool, err := pgxpool.NewWithConfig(ctx, config)
if err != nil {
return nil, fmt.Errorf("failed to create connection pool: %w", err)
}
// Проверка соединения
if err := pool.Ping(ctx); err != nil {
return nil, fmt.Errorf("failed to ping database: %w", err)
}
return pool, nil
}
// getDatabaseURL собирает DATABASE_URL из отдельных переменных или использует готовый
func getDatabaseURL() string {
// Если задан DATABASE_URL, используем его
if url := os.Getenv("DATABASE_URL"); url != "" {
return url
}
// Иначе собираем из отдельных переменных
user := getEnv("DB_USER", "volontery")
password := getEnv("DB_PASSWORD", "volontery")
host := getEnv("DB_HOST", "localhost")
port := getEnv("DB_PORT", "5432")
name := getEnv("DB_NAME", "volontery_db")
sslmode := getEnv("DB_SSLMODE", "disable")
return fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s",
user, password, host, port, name, sslmode)
}
// getEnv получает переменную окружения или возвращает значение по умолчанию
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
// getEnvInt получает целочисленную переменную окружения
func getEnvInt(key string, defaultValue int) int {
if value := os.Getenv(key); value != "" {
if intVal, err := strconv.Atoi(value); err == nil {
return intVal
}
}
return defaultValue
}
// parseDuration парсит duration строку
func parseDuration(s string) time.Duration {
d, err := time.ParseDuration(s)
if err != nil {
return 15 * time.Minute // default
}
return d
}