from pydantic import field_validator from pydantic_settings import BaseSettings, SettingsConfigDict from .timeutil import validate_time_zone class Settings(BaseSettings): model_config = SettingsConfigDict(env_prefix="MONLET_", env_file=".env", extra="ignore") auth_token: str database_url: str = "postgresql+asyncpg://monlet:monlet@127.0.0.1:5432/monlet" log_level: str = "INFO" body_limit_bytes: int = 1_048_576 output_max_bytes: int = 8192 max_batch_events: int = 200 stale_after_sec: int = 90 dead_after_sec: int = 300 detector_tick_sec: int = 15 host: str = "0.0.0.0" port: int = 8000 enable_detector: bool = True enable_notifier_worker: bool = True events_retention_months: int = 36 events_future_partitions: int = 3 event_dedup_retention_days: int = 30 event_dedup_prune_batch_size: int = 5000 partition_maintenance_interval_sec: int = 3600 outbox_retention_max_rows: int = 50_000 notifier_tick_sec: int = 5 notifier_batch_size: int = 20 notifier_max_attempts: int = 8 notifier_lease_sec: int = 300 notifier_http_timeout_sec: float = 10.0 notification_time_zone: str = "UTC" notifier_debug_enabled: bool = True notifier_telegram_enabled: bool = False notifier_telegram_token: str = "" notifier_telegram_chat_id: str = "" notifier_webhook_enabled: bool = False notifier_webhook_url: str = "" notifier_webhook_token: str = "" notifier_alertmanager_enabled: bool = False notifier_alertmanager_url: str = "" @field_validator("auth_token") @classmethod def _validate_auth_token(cls, value: str) -> str: if not value or value == "changeme": raise ValueError("MONLET_AUTH_TOKEN must be set to a non-default value") return value @field_validator("notification_time_zone") @classmethod def _validate_notification_time_zone(cls, value: str) -> str: return validate_time_zone(value) @property def enabled_notifiers(self) -> list[str]: out: list[str] = [] if self.notifier_debug_enabled: out.append("debug") if ( self.notifier_telegram_enabled and self.notifier_telegram_token and self.notifier_telegram_chat_id ): out.append("telegram") if self.notifier_webhook_enabled and self.notifier_webhook_url: out.append("webhook") if self.notifier_alertmanager_enabled and self.notifier_alertmanager_url: out.append("alertmanager") return out @property def sync_database_url(self) -> str: return self.database_url.replace("+asyncpg", "+psycopg") _settings: Settings | None = None def get_settings() -> Settings: global _settings if _settings is None: _settings = Settings() return _settings def reset_settings_cache() -> None: global _settings _settings = None