import os from dataclasses import dataclass, field from pathlib import Path from dotenv import load_dotenv load_dotenv() TRUE_VALUES = {"1", "true", "yes", "on"} # Хелперы для чтения env-переменных с приведением типов def _env_str(name: str, default: str) -> str: value = os.getenv(name) return value if value is not None else default def _env_optional_str(name: str) -> str | None: value = os.getenv(name) if value is None: return None value = value.strip() return value or None def _env_path_str(name: str) -> str | None: value = _env_optional_str(name) if value is None: return None return str(Path(value).expanduser()) def _env_bool(name: str, default: bool) -> bool: fallback = "true" if default else "false" return _env_str(name, fallback).strip().lower() in TRUE_VALUES def _env_int(name: str, default: int) -> int: return int(_env_str(name, str(default)).strip()) def _env_float(name: str, default: float) -> float: return float(_env_str(name, str(default)).strip()) # Конфиг браузерного отпечатка (User-Agent для HTTP запросов) @dataclass(slots=True) class FingerprintConfig: user_agent: str = ( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/135.0.0.0 Safari/537.36" ) # - Конфиг PostgreSQL (URL, пул соединений, pool_recycle) @dataclass(slots=True) class DatabaseConfig: url: str = _env_str("ENCAR_DATABASE_URL", "postgresql+psycopg2://encar:encar@localhost:5434/encar_db") echo: bool = _env_bool("ENCAR_DATABASE_ECHO", False) pool_size: int = _env_int("ENCAR_DATABASE_POOL_SIZE", 5) max_overflow: int = _env_int("ENCAR_DATABASE_MAX_OVERFLOW", 10) pool_recycle_seconds: int = _env_int("ENCAR_DATABASE_POOL_RECYCLE_SECONDS", 1800) auto_create_tables: bool = _env_bool("ENCAR_DATABASE_AUTO_CREATE_TABLES", False) # --- Конфиг Redis (URL для Celery broker) --- @dataclass(slots=True) class RedisConfig: url: str = _env_str("ENCAR_REDIS_URL", "redis://localhost:6380/1") # --- Конфиг Celery (лимиты задач, concurrency, beat-расписание) --- @dataclass(slots=True) class CeleryConfig: broker_url: str = _env_str("CELERY_BROKER_URL", "") result_backend: str = _env_str("CELERY_RESULT_BACKEND", "") task_soft_time_limit: int = _env_int("CELERY_TASK_SOFT_TIME_LIMIT", 14400) task_time_limit: int = _env_int("CELERY_TASK_TIME_LIMIT", 14520) worker_concurrency: int = _env_int("CELERY_WORKER_CONCURRENCY", 4) worker_max_tasks_per_child: int = _env_int("CELERY_WORKER_MAX_TASKS_PER_CHILD", 50) broker_visibility_timeout: int = _env_int("CELERY_BROKER_VISIBILITY_TIMEOUT", 7200) # Encar settings encar_beat_interval_minutes: int = _env_int("ENCAR_BEAT_INTERVAL_MINUTES", 60) encar_beat_limit: int | None = _env_int("ENCAR_BEAT_LIMIT", 0) or None # --- Главный объект настроек: собирает все блоки конфигурации --- @dataclass(slots=True) class Settings: log_level: str = _env_str("ENCAR_LOG_LEVEL", "INFO") log_file: str | None = _env_optional_str("ENCAR_LOG_FILE") fingerprint: FingerprintConfig = field(default_factory=FingerprintConfig) database: DatabaseConfig = field(default_factory=DatabaseConfig) redis: RedisConfig = field(default_factory=RedisConfig) celery: CeleryConfig = field(default_factory=CeleryConfig) # Глобальный синглтон — используется по умолчанию во всех модулях. settings = Settings()