"""Runtime configuration for the backend service.""" from __future__ import annotations import os from dataclasses import dataclass def _env_str(name: str, default: str) -> str: value = os.getenv(name) return value if value not in (None, "") else default def _env_int(name: str, default: int) -> int: value = os.getenv(name) if value in (None, ""): return default return int(value) def _env_float(name: str, default: float) -> float: value = os.getenv(name) if value in (None, ""): return default return float(value) def _env_bool(name: str, default: bool) -> bool: value = os.getenv(name) if value in (None, ""): return default return value.strip().lower() in {"1", "true", "yes", "on"} @dataclass(frozen=True) class BackendSettings: db_dsn: str log_level: str db_pool_min_size: int db_pool_max_size: int broadcaster_queue_maxsize: int packet_tracker_finalize_delay_seconds: float packet_tracker_retention_seconds: float packet_tracker_min_flush_interval_seconds: float packet_tracker_persist_timeout_seconds: float packet_tracker_stop_join_timeout_seconds: float packet_tracker_reject_correlation_window_seconds: float sniffer_buffer_capacity: int sniffer_socket_rcvbuf_bytes: int sniffer_selector_timeout_seconds: float sniffer_recv_bytes: int sniffer_buffer_drain_interval_seconds: float sniffer_thread_join_timeout_seconds: float bridge_bpf_build_dir: str bridge_link_state_thread_join_timeout_seconds: float bridge_link_state_failure_holdoff_seconds: float bridge_link_state_recovery_holdoff_seconds: float bridge_link_state_degraded_recheck_seconds: float telemetry_process_stop_timeout_seconds: float telemetry_reader_join_timeout_seconds: float tshark_enabled: bool tshark_display_filter: str tshark_try_heuristic_first: bool tshark_cache_ttl_seconds: float tshark_match_window_ms: int tshark_reader_join_timeout_seconds: float tshark_process_stop_timeout_seconds: float def load_settings() -> BackendSettings: return BackendSettings( db_dsn=_env_str("BACKEND_DB_DSN", "postgresql://mitm_user:mitm_password@localhost:5432/mitm_db"), log_level=_env_str("BACKEND_LOG_LEVEL", "DEBUG"), db_pool_min_size=_env_int("BACKEND_DB_POOL_MIN_SIZE", 1), db_pool_max_size=_env_int("BACKEND_DB_POOL_MAX_SIZE", 5), broadcaster_queue_maxsize=_env_int("BACKEND_BROADCAST_QUEUE_MAXSIZE", 1024), packet_tracker_finalize_delay_seconds=_env_float("BACKEND_PACKET_TRACKER_FINALIZE_DELAY_SECONDS", 0.25), packet_tracker_retention_seconds=_env_float("BACKEND_PACKET_TRACKER_RETENTION_SECONDS", 10.0), packet_tracker_min_flush_interval_seconds=_env_float("BACKEND_PACKET_TRACKER_MIN_FLUSH_INTERVAL_SECONDS", 0.05), packet_tracker_persist_timeout_seconds=_env_float("BACKEND_PACKET_TRACKER_PERSIST_TIMEOUT_SECONDS", 2.0), packet_tracker_stop_join_timeout_seconds=_env_float("BACKEND_PACKET_TRACKER_STOP_JOIN_TIMEOUT_SECONDS", 2.0), packet_tracker_reject_correlation_window_seconds=_env_float( "BACKEND_PACKET_TRACKER_REJECT_CORRELATION_WINDOW_SECONDS", 1.0, ), sniffer_buffer_capacity=_env_int("BACKEND_SNIFFER_BUFFER_CAPACITY", 20_000), sniffer_socket_rcvbuf_bytes=_env_int("BACKEND_SNIFFER_SOCKET_RCVBUF_BYTES", 4 * 1024 * 1024), sniffer_selector_timeout_seconds=_env_float("BACKEND_SNIFFER_SELECTOR_TIMEOUT_SECONDS", 1.0), sniffer_recv_bytes=_env_int("BACKEND_SNIFFER_RECV_BYTES", 65_536), sniffer_buffer_drain_interval_seconds=_env_float("BACKEND_SNIFFER_BUFFER_DRAIN_INTERVAL_SECONDS", 5.0), sniffer_thread_join_timeout_seconds=_env_float("BACKEND_SNIFFER_THREAD_JOIN_TIMEOUT_SECONDS", 2.0), bridge_bpf_build_dir=_env_str("BACKEND_BRIDGE_BPF_BUILD_DIR", "/tmp/mitm-bpf"), bridge_link_state_thread_join_timeout_seconds=_env_float( "BACKEND_BRIDGE_LINK_STATE_THREAD_JOIN_TIMEOUT_SECONDS", 2.0, ), bridge_link_state_failure_holdoff_seconds=_env_float( "BACKEND_BRIDGE_LINK_STATE_FAILURE_HOLDOFF_SECONDS", 0.75, ), bridge_link_state_recovery_holdoff_seconds=_env_float( "BACKEND_BRIDGE_LINK_STATE_RECOVERY_HOLDOFF_SECONDS", 1.0, ), bridge_link_state_degraded_recheck_seconds=_env_float( "BACKEND_BRIDGE_LINK_STATE_DEGRADED_RECHECK_SECONDS", 0.5, ), telemetry_process_stop_timeout_seconds=_env_float("BACKEND_TELEMETRY_PROCESS_STOP_TIMEOUT_SECONDS", 3.0), telemetry_reader_join_timeout_seconds=_env_float("BACKEND_TELEMETRY_READER_JOIN_TIMEOUT_SECONDS", 2.0), tshark_enabled=_env_bool("BACKEND_TSHARK_ENABLED", True), tshark_display_filter=_env_str("BACKEND_TSHARK_DISPLAY_FILTER", ""), tshark_try_heuristic_first=_env_bool("BACKEND_TSHARK_TRY_HEURISTIC_FIRST", True), tshark_cache_ttl_seconds=_env_float("BACKEND_TSHARK_CACHE_TTL_SECONDS", 5.0), tshark_match_window_ms=_env_int("BACKEND_TSHARK_MATCH_WINDOW_MS", 5_000), tshark_reader_join_timeout_seconds=_env_float("BACKEND_TSHARK_READER_JOIN_TIMEOUT_SECONDS", 2.0), tshark_process_stop_timeout_seconds=_env_float("BACKEND_TSHARK_PROCESS_STOP_TIMEOUT_SECONDS", 3.0), ) settings = load_settings()