| from __future__ import annotations |
|
|
| import hashlib |
| import os |
| from dataclasses import dataclass |
| from pathlib import Path |
|
|
|
|
| def _default_data_dir() -> Path: |
| persistent_root = Path("/data") |
| if persistent_root.exists(): |
| return persistent_root / "scu-course-catcher" |
| return Path("runtime") |
|
|
|
|
| @dataclass(frozen=True) |
| class AppConfig: |
| admin_username: str |
| admin_password: str |
| secret_key: str |
| data_dir: Path |
| database_path: Path |
| chrome_binary: str |
| chromedriver_binary: str |
| default_parallelism: int |
| loop_interval_seconds: float |
| login_retry_limit: int |
| request_timeout_seconds: int |
| debug: bool |
|
|
|
|
| def load_config() -> AppConfig: |
| admin_username = os.getenv("ADMIN", "admin") |
| admin_password = os.getenv("PASSWORD", "change-me-now") |
|
|
| derived_secret = hashlib.sha256( |
| f"{admin_username}:{admin_password}:scu-course-catcher".encode("utf-8") |
| ).hexdigest() |
| secret_key = os.getenv("APP_SECRET", derived_secret) |
|
|
| data_dir = Path(os.getenv("APP_DATA_DIR", str(_default_data_dir()))).resolve() |
| data_dir.mkdir(parents=True, exist_ok=True) |
|
|
| return AppConfig( |
| admin_username=admin_username, |
| admin_password=admin_password, |
| secret_key=secret_key, |
| data_dir=data_dir, |
| database_path=data_dir / "app.db", |
| chrome_binary=os.getenv("CHROME_BIN", "/usr/bin/chromium"), |
| chromedriver_binary=os.getenv("CHROMEDRIVER_BIN", "/usr/bin/chromedriver"), |
| default_parallelism=max(1, int(os.getenv("DEFAULT_PARALLELISM", "1"))), |
| loop_interval_seconds=max(1.0, float(os.getenv("LOOP_INTERVAL_SECONDS", "3"))), |
| login_retry_limit=max(1, int(os.getenv("LOGIN_RETRY_LIMIT", "6"))), |
| request_timeout_seconds=max(15, int(os.getenv("REQUEST_TIMEOUT_SECONDS", "30"))), |
| debug=os.getenv("DEBUG", "").lower() in {"1", "true", "yes", "on"}, |
| ) |
|
|