feat(archive): complete recorded session lifecycle
This commit is contained in:
@@ -218,6 +218,30 @@ class SessionRecordingMaterializer:
|
||||
self._increment_pin_locked(recording.session_id)
|
||||
return self._release_callback(recording.session_id)
|
||||
|
||||
def delete_cached(self, session_id: str) -> bool:
|
||||
"""Delete one exact derived RRD cache unless a response still leases it."""
|
||||
|
||||
if SESSION_ID_PATTERN.fullmatch(session_id) is None:
|
||||
raise ValueError("recording cache session id is invalid")
|
||||
with self._lock_for(session_id), self._cache_guard:
|
||||
if self._pinned_sessions.get(session_id, 0) > 0:
|
||||
return False
|
||||
session_root = self.recordings_root / session_id
|
||||
if session_root.exists() or session_root.is_symlink():
|
||||
metadata = session_root.lstat()
|
||||
if stat.S_ISLNK(metadata.st_mode) or not stat.S_ISDIR(metadata.st_mode):
|
||||
raise RecordingMaterializationError(
|
||||
"session recording cache is not a real directory"
|
||||
)
|
||||
if session_root.parent.resolve(strict=True) != self.recordings_root:
|
||||
raise RecordingMaterializationError(
|
||||
"session recording cache escapes the private data root"
|
||||
)
|
||||
shutil.rmtree(session_root)
|
||||
with self._memory_guard:
|
||||
self._validated_memory.pop(session_id, None)
|
||||
return True
|
||||
|
||||
def __call__(self, command: ReplayCommand) -> MaterializedRecording:
|
||||
"""Alias for :meth:`materialize`, suitable for the web API protocol."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user