aboutsummaryrefslogtreecommitdiffstats
path: root/deckit/config.py
blob: 151207bccb82e0dc0e1c95e721f75cef1bed494e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
"""Configuration loading and validation for deck-it."""

import os
import re
import sys
import tomllib
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent
MONITOR_NAME = re.compile(r"[A-Za-z0-9_-]{1,32}")


def user_config_path() -> Path:
    return Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")) / "deck-it" / "config.toml"


def config_error(cfg: dict) -> str | None:
    d, ports = cfg.get("display", {}), cfg.get("ports", {})
    if not MONITOR_NAME.fullmatch(str(d.get("name", "TAB"))):
        return "display.name must be letters, digits, - or _"
    refresh = d.get("refresh", 60)
    if not isinstance(refresh, int) or not 1 <= refresh <= 240:
        return "display.refresh must be a number from 1 to 240"
    for key in ("command_center", "display"):
        if key in ports:
            v = ports[key]
            if not isinstance(v, int) or not 1024 <= v <= 65535:
                return f"ports.{key} must be a number from 1024 to 65535"
    if ports.get("command_center", 8765) == ports.get("display", 5900):
        return "ports.command_center and ports.display must differ"
    return None


def load_config() -> dict:
    path = user_config_path() if user_config_path().is_file() else ROOT / "config.toml"
    with open(path, "rb") as f:
        cfg = tomllib.load(f)
    if err := config_error(cfg):
        sys.exit(f"{path}: {err}")
    return cfg