mirror of
https://github.com/hanzoskill/llm-council.git
synced 2026-10-30 21:14:09 +00:00
70 lines
2.5 KiB
Python
70 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
import json
|
|
import threading
|
|
from copy import deepcopy
|
|
from pathlib import Path
|
|
from typing import Any, Callable, Dict, Optional
|
|
|
|
|
|
class UIState:
|
|
def __init__(
|
|
self,
|
|
initial: Optional[Dict[str, Any]] = None,
|
|
snapshot_path: Optional[Path] = None,
|
|
publish: Optional[Callable[[Dict[str, Any]], None]] = None,
|
|
) -> None:
|
|
self._lock = threading.Lock()
|
|
self._state: Dict[str, Any] = deepcopy(initial) if initial else {}
|
|
self._snapshot_path = snapshot_path
|
|
self._publish = publish
|
|
if self._snapshot_path is not None:
|
|
self._snapshot_path.parent.mkdir(parents=True, exist_ok=True)
|
|
self._write_snapshot(self._state)
|
|
|
|
def get(self) -> Dict[str, Any]:
|
|
with self._lock:
|
|
return deepcopy(self._state)
|
|
|
|
def set(self, state: Dict[str, Any], *, snapshot: bool = True) -> None:
|
|
with self._lock:
|
|
self._state = deepcopy(state)
|
|
snapshot_payload = deepcopy(self._state)
|
|
if snapshot:
|
|
self._write_snapshot(snapshot_payload)
|
|
|
|
def update(self, patch: Dict[str, Any], *, snapshot: bool = True) -> None:
|
|
with self._lock:
|
|
for key, value in patch.items():
|
|
self._state[key] = deepcopy(value)
|
|
snapshot_payload = deepcopy(self._state)
|
|
if snapshot:
|
|
self._write_snapshot(snapshot_payload)
|
|
|
|
def mutate(self, mutator: Callable[[Dict[str, Any]], None], *, snapshot: bool = True) -> None:
|
|
with self._lock:
|
|
mutator(self._state)
|
|
snapshot_payload = deepcopy(self._state)
|
|
if snapshot:
|
|
self._write_snapshot(snapshot_payload)
|
|
|
|
def publish(self, event_type: str, payload: Dict[str, Any]) -> None:
|
|
if not self._publish:
|
|
return
|
|
event = {"type": event_type, "payload": payload}
|
|
self._publish(event)
|
|
|
|
def _write_snapshot(self, payload: Dict[str, Any]) -> None:
|
|
if self._snapshot_path is None:
|
|
return
|
|
tmp_path = self._snapshot_path.with_suffix(self._snapshot_path.suffix + ".tmp")
|
|
try:
|
|
with open(tmp_path, "w", encoding="utf-8") as handle:
|
|
json.dump(payload, handle, indent=2, sort_keys=True, ensure_ascii=False)
|
|
tmp_path.replace(self._snapshot_path)
|
|
except OSError:
|
|
try:
|
|
if tmp_path.exists():
|
|
tmp_path.unlink()
|
|
except OSError:
|
|
pass
|