Update Athena runtimes and sync live extensions
This commit is contained in:
@@ -54,10 +54,12 @@ class UnixConnection(http.client.HTTPConnection):
|
||||
self.sock.connect(SOCKET_PATH)
|
||||
|
||||
|
||||
def docker_request(method: str, path: str) -> tuple[int, bytes]:
|
||||
def docker_request(method: str, path: str, payload: dict | None = None) -> tuple[int, bytes]:
|
||||
conn = UnixConnection("localhost", timeout=30)
|
||||
try:
|
||||
conn.request(method, path, headers={"Content-Type": "application/json"})
|
||||
body = json.dumps(payload).encode() if payload is not None else None
|
||||
conn.request(method, path, body=body,
|
||||
headers={"Content-Type": "application/json"})
|
||||
response = conn.getresponse()
|
||||
return response.status, response.read()
|
||||
finally:
|
||||
@@ -200,6 +202,69 @@ def video_container() -> dict:
|
||||
return matches[0]
|
||||
|
||||
|
||||
def docker_exec(item: dict, command: str) -> str:
|
||||
status, body = docker_request("POST", f"/containers/{item['Id']}/exec", {
|
||||
"AttachStdout": True, "AttachStderr": True, "Tty": True,
|
||||
"Cmd": ["/bin/sh", "-c", command],
|
||||
})
|
||||
if status != 201:
|
||||
raise RuntimeError(f"failed to create container exec: HTTP {status}")
|
||||
exec_id = json.loads(body)["Id"]
|
||||
status, body = docker_request("POST", f"/exec/{exec_id}/start",
|
||||
{"Detach": False, "Tty": True})
|
||||
if status != 200:
|
||||
raise RuntimeError(f"failed to start container exec: HTTP {status}")
|
||||
return body.decode(errors="replace").strip()
|
||||
|
||||
|
||||
VIDEO_UI_PROCESSES = r'''for p in /proc/[0-9]*; do
|
||||
[ -r "$p/cmdline" ] || continue
|
||||
exe=$(readlink "$p/exe" 2>/dev/null) || continue
|
||||
c=$(tr '\000' ' ' < "$p/cmdline")
|
||||
case "${exe##*/}:$c" in
|
||||
ltx-desktop:*--type=*)
|
||||
printf '%s\n' "${p##*/}";;
|
||||
esac
|
||||
done'''
|
||||
|
||||
VIDEO_UI_STATE: str | None = None
|
||||
|
||||
|
||||
def video_ui_state(item: dict | None = None) -> str:
|
||||
item = item or video_container()
|
||||
if item.get("State") != "running":
|
||||
return "unavailable"
|
||||
output = docker_exec(item, VIDEO_UI_PROCESSES + r''' | while read p; do
|
||||
state=$(sed -n 's/^State:[[:space:]]*\([A-Z]\).*/\1/p' "/proc/$p/status")
|
||||
printf '%s\n' "$state"
|
||||
done''')
|
||||
states = [line.strip() for line in output.splitlines() if line.strip()]
|
||||
if not states:
|
||||
return "unavailable"
|
||||
return "sleeping" if all(state == "T" for state in states) else "awake"
|
||||
|
||||
|
||||
def cached_video_ui_state(item: dict | None = None) -> str:
|
||||
global VIDEO_UI_STATE
|
||||
if VIDEO_UI_STATE is None:
|
||||
VIDEO_UI_STATE = video_ui_state(item)
|
||||
return VIDEO_UI_STATE
|
||||
|
||||
|
||||
def set_video_ui(awake: bool) -> dict:
|
||||
global VIDEO_UI_STATE
|
||||
with LOCK:
|
||||
item = video_container()
|
||||
if item.get("State") != "running":
|
||||
raise RuntimeError("LTX-2 is not running")
|
||||
signal = "CONT" if awake else "STOP"
|
||||
docker_exec(item, VIDEO_UI_PROCESSES +
|
||||
f''' | while read p; do kill -{signal} "$p"; done''')
|
||||
time.sleep(0.25)
|
||||
VIDEO_UI_STATE = video_ui_state(item)
|
||||
return {"video_ui": VIDEO_UI_STATE}
|
||||
|
||||
|
||||
def stop_video_if_configured() -> None:
|
||||
if VIDEO_WORKER:
|
||||
stop_container(video_container(), timeout=30)
|
||||
@@ -482,6 +547,7 @@ def set_trellis_worker(running: bool) -> dict:
|
||||
|
||||
def set_video_worker(running: bool) -> dict:
|
||||
"""Start LTX-2 exclusively, or stop it before another mode is loaded."""
|
||||
global VIDEO_UI_STATE
|
||||
with LOCK:
|
||||
item = video_container()
|
||||
if running:
|
||||
@@ -496,8 +562,10 @@ def set_video_worker(running: bool) -> dict:
|
||||
stop_voice_tools()
|
||||
stop_trellis_if_configured()
|
||||
start_container(item)
|
||||
VIDEO_UI_STATE = "awake"
|
||||
else:
|
||||
stop_container(item, timeout=30)
|
||||
VIDEO_UI_STATE = "unavailable"
|
||||
return {"video_worker": VIDEO_WORKER,
|
||||
"state": "running" if running else "stopped"}
|
||||
|
||||
@@ -660,6 +728,7 @@ class Handler(BaseHTTPRequestHandler):
|
||||
"trellis_health": trellis_health,
|
||||
"video_worker": video.get("State", "disabled"),
|
||||
"video_health": video_health,
|
||||
"video_ui": cached_video_ui_state(video) if video else "unavailable",
|
||||
"profiles": {name: items.get(name, {}).get(
|
||||
"State", "missing") for name in ALLOWED}})
|
||||
except Exception as exc:
|
||||
@@ -733,6 +802,13 @@ class Handler(BaseHTTPRequestHandler):
|
||||
log.exception("video worker transition failed")
|
||||
self.reply(503, {"error": str(exc)})
|
||||
return
|
||||
if self.path in {"/workers/video/ui/sleep", "/workers/video/ui/wake"}:
|
||||
try:
|
||||
self.reply(200, set_video_ui(self.path.endswith("/wake")))
|
||||
except Exception as exc:
|
||||
log.exception("video UI transition failed")
|
||||
self.reply(503, {"error": str(exc)})
|
||||
return
|
||||
worker_paths = {
|
||||
"/workers/image/start": (IMAGE_WORKER, True),
|
||||
"/workers/image/stop": (IMAGE_WORKER, False),
|
||||
|
||||
Reference in New Issue
Block a user