769e76313f
- Recovery middleware (no more crash-on-panic), request metrics/monitoring store + admin API, in-memory TTL caching for read-heavy option/question/ category lookups, gzip + rate-limiting middleware, sanitized chat message encoding, and pg_dump-based database backups with an admin API. - Fix N+1 queries in the discover feed, candidate detail, and match list endpoints by batching selection/photo/user/last-message lookups into single queries instead of one-per-item loops. - Tune DB connection pooling and add HTTP server timeouts + graceful shutdown so the API degrades gracefully instead of falling over under load. - Fix a null (vs empty array) JSON response for candidates/matches without photos or interests, which crashed the web app's swipe card.
102 lines
3.0 KiB
Go
102 lines
3.0 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/joho/godotenv"
|
|
)
|
|
|
|
// Config تمام تنظیمات قابلپیکربندی برنامه از طریق متغیرهای محیطی
|
|
type Config struct {
|
|
AppEnv string
|
|
AppPort string
|
|
|
|
DBHost string
|
|
DBPort string
|
|
DBUser string
|
|
DBPassword string
|
|
DBName string
|
|
DBSSLMode string
|
|
|
|
// تنظیمات connection pool؛ زیر بار بالا اینها از باز شدن بیرویهی اتصال
|
|
// (که خود Postgres رو زمین میزنه) و از نشتی اتصالات راکد جلوگیری میکنن.
|
|
DBMaxOpenConns int
|
|
DBMaxIdleConns int
|
|
DBConnMaxLifetimeMins int
|
|
DBConnMaxIdleTimeMins int
|
|
|
|
JWTAccessSecret string
|
|
JWTRefreshSecret string
|
|
JWTAccessTTL time.Duration
|
|
JWTRefreshTTL time.Duration
|
|
|
|
OTPExpirySeconds int
|
|
OTPLength int
|
|
OTPHashSecret string
|
|
|
|
// اگر پر باشد، در اولین اجرا یک کاربر ادمین با این شماره ساخته میشود
|
|
AdminBootstrapPhone string
|
|
}
|
|
|
|
// Load فایل .env را (در صورت وجود) میخواند و Config را برمیگرداند.
|
|
// نبودن فایل .env خطا محسوب نمیشود (مثلاً در پروداکشن env مستقیم ست میشود).
|
|
func Load() *Config {
|
|
_ = godotenv.Load()
|
|
|
|
return &Config{
|
|
AppEnv: getEnv("APP_ENV", "development"),
|
|
AppPort: getEnv("APP_PORT", "8080"),
|
|
|
|
DBHost: getEnv("DB_HOST", "localhost"),
|
|
DBPort: getEnv("DB_PORT", "5432"),
|
|
DBUser: getEnv("DB_USER", "postgres"),
|
|
DBPassword: getEnv("DB_PASSWORD", "postgres"),
|
|
DBName: getEnv("DB_NAME", "dating_app"),
|
|
DBSSLMode: getEnv("DB_SSLMODE", "disable"),
|
|
|
|
DBMaxOpenConns: getEnvInt("DB_MAX_OPEN_CONNS", 25),
|
|
DBMaxIdleConns: getEnvInt("DB_MAX_IDLE_CONNS", 10),
|
|
DBConnMaxLifetimeMins: getEnvInt("DB_CONN_MAX_LIFETIME_MINUTES", 30),
|
|
DBConnMaxIdleTimeMins: getEnvInt("DB_CONN_MAX_IDLE_TIME_MINUTES", 5),
|
|
|
|
JWTAccessSecret: getEnv("JWT_ACCESS_SECRET", "change-me-access-secret"),
|
|
JWTRefreshSecret: getEnv("JWT_REFRESH_SECRET", "change-me-refresh-secret"),
|
|
JWTAccessTTL: time.Duration(getEnvInt("JWT_ACCESS_TTL_MINUTES", 60*24)) * time.Minute,
|
|
JWTRefreshTTL: time.Duration(getEnvInt("JWT_REFRESH_TTL_DAYS", 30)) * 24 * time.Hour,
|
|
|
|
OTPExpirySeconds: getEnvInt("OTP_EXPIRY_SECONDS", 180),
|
|
OTPLength: getEnvInt("OTP_LENGTH", 4),
|
|
OTPHashSecret: getEnv("OTP_HASH_SECRET", "change-me-otp-secret"),
|
|
|
|
AdminBootstrapPhone: getEnv("ADMIN_BOOTSTRAP_PHONE", ""),
|
|
}
|
|
}
|
|
|
|
func (c *Config) DSN() string {
|
|
return "host=" + c.DBHost +
|
|
" user=" + c.DBUser +
|
|
" password=" + c.DBPassword +
|
|
" dbname=" + c.DBName +
|
|
" port=" + c.DBPort +
|
|
" sslmode=" + c.DBSSLMode +
|
|
" TimeZone=Asia/Tehran"
|
|
}
|
|
|
|
func getEnv(key, fallback string) string {
|
|
if v := os.Getenv(key); v != "" {
|
|
return v
|
|
}
|
|
return fallback
|
|
}
|
|
|
|
func getEnvInt(key string, fallback int) int {
|
|
if v := os.Getenv(key); v != "" {
|
|
if n, err := strconv.Atoi(v); err == nil {
|
|
return n
|
|
}
|
|
}
|
|
return fallback
|
|
}
|