Files
KH_Clock/config.py

91 lines
2.9 KiB
Python

import re
import secrets
import sys
from dataclasses import dataclass
from pathlib import Path
try:
import tomllib
except ImportError:
try:
import tomli as tomllib # type: ignore[no-redef]
except ImportError:
print("Error: Python 3.11+ is required (for tomllib), or install tomli: pip install tomli")
sys.exit(1)
CONFIG_PATH = Path("config.toml")
@dataclass
class AppConfig:
width: int | None
height: int | None
fps: int
clock_font_path: str
message_font_path: str
port: int
default_duration: float
api_token: str
rate_limit: int
password_hash: str
session_timeout_hours: int
config_path: Path
@classmethod
def load(cls, path: str | Path = CONFIG_PATH) -> "AppConfig":
p = Path(path)
if not p.exists():
print(f"Error: Config file not found: {p}")
print("Copy config.toml to your working directory and edit it.")
sys.exit(1)
with open(p, "rb") as f:
raw = tomllib.load(f)
display = raw.get("display", {})
server = raw.get("server", {})
api = raw.get("api", {})
rate = raw.get("rate_limit", {})
dashboard = raw.get("dashboard", {})
token = api.get("token", "").strip()
if not token:
token = secrets.token_hex(32)
_update_config_field(p, "token", token)
print(f"\n[KH-clock] Generated API bearer token (saved to config.toml):")
print(f" {token}\n")
return cls(
width=display.get("width"),
height=display.get("height"),
fps=display.get("fps", 10),
clock_font_path=display.get("clock_font_path", "").strip(),
message_font_path=display.get("message_font_path", "").strip(),
port=server.get("port", 8080),
default_duration=float(server.get("default_duration_seconds", 20)),
api_token=token,
rate_limit=rate.get("requests_per_minute", 20),
password_hash=dashboard.get("password_hash", "").strip(),
session_timeout_hours=dashboard.get("session_timeout_hours", 8),
config_path=p,
)
def save_password_hash(self, hashed: str) -> None:
_update_config_field(self.config_path, "password_hash", hashed)
self.password_hash = hashed
def _update_config_field(config_path: Path, key: str, value: str) -> None:
"""Update a quoted string field in config.toml using regex replacement."""
content = config_path.read_text()
pattern = rf'^({re.escape(key)}\s*=\s*)"[^"]*"'
def replacer(m: re.Match) -> str:
return f'{m.group(1)}"{value}"'
new_content = re.sub(pattern, replacer, content, flags=re.MULTILINE)
if new_content == content:
print(f"Warning: Could not update '{key}' in {config_path}. Field not found.")
return
config_path.write_text(new_content)