Init
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
from threading import Lock
|
||||
|
||||
from led_platform.core.clock import epoch_ms
|
||||
from led_platform.domain import Scene, SceneState
|
||||
|
||||
|
||||
class SceneStore:
|
||||
def __init__(self, config_path: Path) -> None:
|
||||
self.config_path = config_path
|
||||
self._lock = Lock()
|
||||
self._scenes: dict[str, Scene] = {}
|
||||
self._state: SceneState | None = None
|
||||
self.reload()
|
||||
|
||||
def reload(self) -> None:
|
||||
data = json.loads(self.config_path.read_text(encoding="utf-8"))
|
||||
scenes = [Scene(**item) for item in data["scenes"]]
|
||||
if not scenes:
|
||||
raise ValueError("At least one scene is required.")
|
||||
default_scene_id = data.get("default_scene_id") or scenes[0].id
|
||||
scene_map = {scene.id: scene for scene in scenes}
|
||||
if default_scene_id not in scene_map:
|
||||
raise ValueError(f"Default scene {default_scene_id!r} does not exist.")
|
||||
default_scene = scene_map[default_scene_id]
|
||||
with self._lock:
|
||||
version = self._state.version + 1 if self._state else 1
|
||||
self._scenes = scene_map
|
||||
self._state = self._build_state(default_scene, version=version, apply_at_ms=None)
|
||||
|
||||
def list(self) -> list[Scene]:
|
||||
with self._lock:
|
||||
return list(self._scenes.values())
|
||||
|
||||
def get(self, scene_id: str) -> Scene:
|
||||
with self._lock:
|
||||
if scene_id not in self._scenes:
|
||||
raise KeyError(scene_id)
|
||||
return self._scenes[scene_id]
|
||||
|
||||
def state(self) -> SceneState:
|
||||
with self._lock:
|
||||
if self._state is None:
|
||||
raise RuntimeError("Scene state is not initialized.")
|
||||
return self._state
|
||||
|
||||
def switch(self, scene_id: str, apply_at_ms: int) -> SceneState:
|
||||
with self._lock:
|
||||
if scene_id not in self._scenes:
|
||||
raise KeyError(scene_id)
|
||||
version = self._state.version + 1 if self._state else 1
|
||||
self._state = self._build_state(
|
||||
self._scenes[scene_id],
|
||||
version=version,
|
||||
apply_at_ms=apply_at_ms,
|
||||
)
|
||||
return self._state
|
||||
|
||||
def action(self, action: str, apply_at_ms: int) -> SceneState:
|
||||
with self._lock:
|
||||
if self._state is None:
|
||||
raise RuntimeError("Scene state is not initialized.")
|
||||
self._state = self._state.model_copy(
|
||||
update={
|
||||
"version": self._state.version + 1,
|
||||
"action": action,
|
||||
"apply_at_ms": apply_at_ms,
|
||||
}
|
||||
)
|
||||
return self._state
|
||||
|
||||
@staticmethod
|
||||
def _build_state(scene: Scene, version: int, apply_at_ms: int | None) -> SceneState:
|
||||
return SceneState(
|
||||
active_scene_id=scene.id,
|
||||
active_view=scene.view,
|
||||
active_url=str(scene.url),
|
||||
version=version,
|
||||
scene_started_at_ms=apply_at_ms or epoch_ms(),
|
||||
apply_at_ms=apply_at_ms,
|
||||
)
|
||||
Reference in New Issue
Block a user