first commit
This commit is contained in:
commit
dc1245f164
22 changed files with 1666 additions and 0 deletions
101
monitor/config.py
Normal file
101
monitor/config.py
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
"""Configuration loading and validation."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import yaml
|
||||
|
||||
from monitor.models import (
|
||||
AppConfig,
|
||||
BrowserConfig,
|
||||
MonitorConfig,
|
||||
NotificationChannelConfig,
|
||||
NotificationsConfig,
|
||||
WebsiteConfig,
|
||||
)
|
||||
|
||||
|
||||
def _channel_config(data: dict[str, Any] | None) -> NotificationChannelConfig:
|
||||
if not data:
|
||||
return NotificationChannelConfig()
|
||||
return NotificationChannelConfig(enabled=bool(data.get("enabled", False)))
|
||||
|
||||
|
||||
def load_config(path: str | Path) -> AppConfig:
|
||||
"""Load application configuration from a YAML file."""
|
||||
config_path = Path(path)
|
||||
if not config_path.exists():
|
||||
raise FileNotFoundError(f"Configuration file not found: {config_path}")
|
||||
|
||||
with config_path.open("r", encoding="utf-8") as handle:
|
||||
raw: dict[str, Any] = yaml.safe_load(handle) or {}
|
||||
|
||||
browser_raw = raw.get("browser", {})
|
||||
monitor_raw = raw.get("monitor", {})
|
||||
notifications_raw = raw.get("notifications", {})
|
||||
|
||||
browser = BrowserConfig(
|
||||
type=str(browser_raw.get("type", "chrome")).lower(),
|
||||
executable_path=browser_raw.get("executable_path"),
|
||||
headless=bool(browser_raw.get("headless", False)),
|
||||
profile_directory=str(browser_raw.get("profile_directory", "./profiles/default")),
|
||||
)
|
||||
|
||||
monitor = MonitorConfig(
|
||||
round_robin_delay_seconds=float(monitor_raw.get("round_robin_delay_seconds", 5)),
|
||||
page_load_timeout_seconds=float(monitor_raw.get("page_load_timeout_seconds", 30)),
|
||||
render_wait_seconds=float(monitor_raw.get("render_wait_seconds", 3)),
|
||||
snapshot_directory=str(monitor_raw.get("snapshot_directory", "./snapshots")),
|
||||
snapshot_retention_count=int(monitor_raw.get("snapshot_retention_count", 50)),
|
||||
browser_restart_max_retries=int(monitor_raw.get("browser_restart_max_retries", 3)),
|
||||
browser_restart_backoff_seconds=float(
|
||||
monitor_raw.get("browser_restart_backoff_seconds", 5)
|
||||
),
|
||||
)
|
||||
|
||||
websites: list[WebsiteConfig] = []
|
||||
for entry in raw.get("websites", []):
|
||||
known_keys = {"id", "name", "url", "enabled"}
|
||||
extra = {k: v for k, v in entry.items() if k not in known_keys}
|
||||
websites.append(
|
||||
WebsiteConfig(
|
||||
id=str(entry["id"]),
|
||||
name=str(entry.get("name", entry["id"])),
|
||||
url=str(entry["url"]),
|
||||
enabled=bool(entry.get("enabled", True)),
|
||||
extra=extra,
|
||||
)
|
||||
)
|
||||
|
||||
notifications = NotificationsConfig(
|
||||
sms=_channel_config(notifications_raw.get("sms")),
|
||||
email=_channel_config(notifications_raw.get("email")),
|
||||
)
|
||||
|
||||
return AppConfig(
|
||||
browser=browser,
|
||||
monitor=monitor,
|
||||
websites=websites,
|
||||
notifications=notifications,
|
||||
)
|
||||
|
||||
|
||||
def load_env_file(path: str | Path = ".env") -> None:
|
||||
"""Load simple KEY=VALUE pairs from a .env file into os.environ."""
|
||||
env_path = Path(path)
|
||||
if not env_path.exists():
|
||||
return
|
||||
|
||||
with env_path.open("r", encoding="utf-8") as handle:
|
||||
for line in handle:
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
key, value = line.split("=", 1)
|
||||
key = key.strip()
|
||||
value = value.strip().strip('"').strip("'")
|
||||
if key and key not in os.environ:
|
||||
os.environ[key] = value
|
||||
Loading…
Add table
Add a link
Reference in a new issue