feat(observatory): cache sealed camera and TGS replay on Core

This commit is contained in:
DCCONSTRUCTIONS
2026-09-03 13:15:07 +03:00
parent 3ea8d987a7
commit 27979854a7
6 changed files with 907 additions and 2 deletions
+17
View File
@@ -54,6 +54,7 @@ from k1link.observatory.portable_queue_binding import (
PortableQueueBindingError,
PortableRecordedQueueBindingService,
)
from k1link.observatory.portable_replay import PortableReplayService
from k1link.observatory.portable_result_cache import PortableResultCache
from k1link.observatory.portable_result_contract import (
PortableCalculationProfileRegistry,
@@ -212,6 +213,7 @@ from k1link.web.plugin_runtime import (
PluginRuntimeUnavailableError,
)
from k1link.web.polygon_api import build_polygon_router, configured_polygon_runs_root
from k1link.web.portable_replay_api import build_portable_replay_router
from k1link.web.runtime_diagnostics import configure_scanner_diagnostics
from k1link.web.runtime_readiness import (
BackgroundReconcilerReadiness,
@@ -1053,6 +1055,21 @@ async def device_plugin_events(websocket: WebSocket, plugin_id: str) -> None:
await websocket.close(code=1011, reason="Device plugin state stream failed")
if session_artifact_gateway is not None and _ffmpeg is not None:
app.include_router(
build_portable_replay_router(
PortableReplayService(
view=PortableResultViewService(
sessions=session_store, artifacts=session_artifact_gateway.store
),
data_dir=session_store.data_dir,
media=session_recorded_media_inspector,
recording_source=_canonical_lab_recording_source,
ffmpeg_path=_ffmpeg,
)
)
)
for legacy_router in plugin_environment.legacy_routers:
app.include_router(legacy_router)
+75
View File
@@ -0,0 +1,75 @@
"""Same-origin immutable replay derivatives; GET never starts packaging."""
from __future__ import annotations
import logging
from typing import Annotated
from fastapi import APIRouter, HTTPException, Path, Query, Response
from fastapi.responses import FileResponse
from k1link.laboratory.canonical_rerun_overlay import CanonicalLabOverlayError
from k1link.observatory.portable_replay import PortableReplayService
from k1link.observatory.portable_result_view import PortableResultViewError
ResultId = Annotated[str, Path(pattern=r"^m49-tgs-portable-review-[a-f0-9]{64}$")]
BaseSha = Annotated[str, Path(pattern=r"^[a-f0-9]{64}$")]
_LOG = logging.getLogger(__name__)
def build_portable_replay_router(service: PortableReplayService) -> APIRouter:
router = APIRouter(tags=["observatory"])
path = "/api/v1/observatory/portable-results/{result_id}/replays/{base_sha}/recording.rrd"
@router.head(path)
def prepare(result_id: ResultId, base_sha: BaseSha) -> Response:
try:
artifact = service.prepare(result_id, base_sha)
except (
ValueError,
OSError,
KeyError,
TypeError,
CanonicalLabOverlayError,
PortableResultViewError,
) as exc:
_LOG.exception("Portable replay packaging rejected")
raise HTTPException(
409, "Сохранённый результат не удалось подготовить к просмотру."
) from exc
return Response(
media_type="application/vnd.rerun.rrd",
headers={
"Content-Length": str(artifact.byte_length),
"ETag": f'"{artifact.sha256}"',
"X-Rerun-Format": "RRF2",
"Cache-Control": "private, no-store",
},
)
@router.get(path)
def read(
result_id: ResultId,
base_sha: BaseSha,
generation: Annotated[str, Query(pattern=r"^[a-f0-9]{64}$")],
) -> FileResponse:
try:
artifact = service.cached(result_id, base_sha)
except (ValueError, OSError, KeyError, TypeError, PortableResultViewError) as exc:
raise HTTPException(409, "Кэш результата не прошёл проверку.") from exc
if artifact is None:
raise HTTPException(409, "Сохранённый просмотр ещё не подготовлен.")
if artifact.sha256 != generation:
raise HTTPException(412, "Версия сохранённого просмотра изменилась.")
return FileResponse(
artifact.path,
media_type="application/vnd.rerun.rrd",
headers={
"ETag": f'"{artifact.sha256}"',
"X-Rerun-Format": "RRF2",
"Cache-Control": "private, max-age=31536000, immutable",
"X-Content-Type-Options": "nosniff",
},
)
return router