65 lines
2.2 KiB
Python
65 lines
2.2 KiB
Python
"""Persistent session-state helpers for GUI-only runtime preferences."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
import json
|
|
import logging
|
|
from pathlib import Path
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class GuiSessionState:
|
|
"""Small persisted GUI session state."""
|
|
|
|
last_profile_path: str = ""
|
|
|
|
|
|
class GuiSessionStateStore:
|
|
"""Atomic JSON store for GUI session-state file."""
|
|
|
|
def __init__(self, path: Path) -> None:
|
|
"""Create store targeting `path`."""
|
|
self._path = path
|
|
self._path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
@property
|
|
def path(self) -> Path:
|
|
"""Return backing session-state file path."""
|
|
return self._path
|
|
|
|
def load(self) -> GuiSessionState:
|
|
"""Load session-state from disk or return empty defaults when missing."""
|
|
if not self._path.exists():
|
|
return GuiSessionState()
|
|
|
|
try:
|
|
payload = json.loads(self._path.read_text(encoding="utf-8"))
|
|
except (OSError, json.JSONDecodeError) as exc:
|
|
# The state file is GUI-local cache — a corrupted file should not
|
|
# prevent the app from starting. Reset to defaults and let the
|
|
# next write overwrite it.
|
|
logger.warning("Resetting unreadable GUI session-state %s: %s", self._path, exc)
|
|
return GuiSessionState()
|
|
if not isinstance(payload, dict):
|
|
logger.warning("Resetting GUI session-state with non-object root: %s", self._path)
|
|
return GuiSessionState()
|
|
|
|
raw_path = payload.get("last_profile_path", "")
|
|
if not isinstance(raw_path, str):
|
|
logger.warning("Resetting GUI session-state with non-string last_profile_path: %s", self._path)
|
|
return GuiSessionState()
|
|
return GuiSessionState(last_profile_path=raw_path)
|
|
|
|
def write(self, state: GuiSessionState) -> Path:
|
|
"""Atomically write session-state JSON file."""
|
|
temp_path = self._path.with_suffix(self._path.suffix + ".tmp")
|
|
temp_path.write_text(
|
|
json.dumps({"last_profile_path": state.last_profile_path}, indent=2),
|
|
encoding="utf-8",
|
|
)
|
|
temp_path.replace(self._path)
|
|
return self._path
|