mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-11 19:45:06 +00:00
refactor(api): simplify leftovers from the perf pass
This commit is contained in:
@@ -4198,9 +4198,6 @@ async def session_tracks_handler(
|
||||
except (Exception, SystemExit):
|
||||
session.chapters_by_title[str(title_id)] = []
|
||||
|
||||
video_tracks = sorted(tracks.videos, key=lambda t: t.bitrate or 0, reverse=True)
|
||||
audio_tracks = sorted(tracks.audio, key=lambda t: t.bitrate or 0, reverse=True)
|
||||
|
||||
manifests, track_manifests = await asyncio.to_thread(
|
||||
lambda: (extract_manifests(tracks), extract_track_manifests(tracks))
|
||||
)
|
||||
@@ -4238,27 +4235,21 @@ async def session_tracks_handler(
|
||||
else:
|
||||
server_cdm_type = "playready"
|
||||
|
||||
def serialize() -> tuple[list, list, list, list]:
|
||||
def serialize() -> Dict[str, list]:
|
||||
"""The track and attachment lists, off the event loop: an attachment can be a 20 MB file."""
|
||||
lists = serialize_tracks(tracks, title, include_url=True)
|
||||
for d in lists["video"] + lists["audio"] + lists["subtitles"]:
|
||||
d["data"] = scrub_track_data(d.get("data"), session)
|
||||
attachments = [a for a in map(serialize_attachment, tracks.attachments) if a]
|
||||
return lists["video"], lists["audio"], lists["subtitles"], attachments
|
||||
|
||||
video, audio, subtitles, attachments = await asyncio.to_thread(serialize)
|
||||
return {**lists, "attachments": [a for a in map(serialize_attachment, tracks.attachments) if a]}
|
||||
|
||||
return web.json_response(
|
||||
{
|
||||
"title": stamp_service_flags(serialize_title(title), service_instance),
|
||||
"video": video,
|
||||
"audio": audio,
|
||||
"subtitles": subtitles,
|
||||
**await asyncio.to_thread(serialize),
|
||||
"chapters": [
|
||||
{"timestamp": ch.timestamp, "name": ch.name}
|
||||
for ch in session.chapters_by_title.get(str(title_id), [])
|
||||
],
|
||||
"attachments": attachments,
|
||||
"manifests": manifests,
|
||||
"track_manifests": track_manifests,
|
||||
"session_headers": session_headers,
|
||||
@@ -4267,7 +4258,7 @@ async def session_tracks_handler(
|
||||
"server_cdm": session.server_cdm,
|
||||
"server_cdm_type": server_cdm_type,
|
||||
"sample_decrypt_tracks": [
|
||||
str(t.id) for t in [*video_tracks, *audio_tracks] if service_instance.decrypts_samples(t)
|
||||
str(t.id) for t in [*tracks.videos, *tracks.audio] if service_instance.decrypts_samples(t)
|
||||
],
|
||||
}
|
||||
)
|
||||
@@ -4547,8 +4538,7 @@ async def get_validated_session(session_id: str, request: Optional[web.Request])
|
||||
details={"session_id": session_id},
|
||||
)
|
||||
if session.owner_key is not None and request is not None:
|
||||
caller_key = request.headers.get("X-Secret-Key", "anonymous")
|
||||
if not hmac.compare_digest(caller_key, session.owner_key):
|
||||
if not hmac.compare_digest(caller_key(request), session.owner_key):
|
||||
raise APIError(
|
||||
APIErrorCode.FORBIDDEN,
|
||||
"Session access denied",
|
||||
|
||||
@@ -207,16 +207,15 @@ def heartbeat(handler: Handler) -> Handler:
|
||||
|
||||
|
||||
UPDATE_CHECK_TTL = 300.0
|
||||
UPDATE_CHECK: dict[str, tuple[float, Optional[str]]] = {}
|
||||
UPDATE_CHECK: list[tuple[float, Optional[str]]] = []
|
||||
|
||||
|
||||
def latest_release() -> Optional[str]:
|
||||
async def latest_release() -> Optional[str]:
|
||||
"""The newer release the update check reports, kept for ``UPDATE_CHECK_TTL`` seconds: clients poll health."""
|
||||
hit = UPDATE_CHECK.get(__version__)
|
||||
if hit and time.monotonic() - hit[0] < UPDATE_CHECK_TTL:
|
||||
return hit[1]
|
||||
latest = UpdateChecker.check_for_updates_sync(__version__)
|
||||
UPDATE_CHECK[__version__] = (time.monotonic(), latest)
|
||||
if UPDATE_CHECK and time.monotonic() - UPDATE_CHECK[0][0] < UPDATE_CHECK_TTL:
|
||||
return UPDATE_CHECK[0][1]
|
||||
latest = await asyncio.to_thread(UpdateChecker.check_for_updates_sync, __version__)
|
||||
UPDATE_CHECK[:] = [(time.monotonic(), latest)]
|
||||
return latest
|
||||
|
||||
|
||||
@@ -261,7 +260,7 @@ async def health(request: web.Request) -> web.Response:
|
||||
nullable: true
|
||||
"""
|
||||
try:
|
||||
latest_version = await asyncio.to_thread(latest_release)
|
||||
latest_version = await latest_release()
|
||||
update_info = {
|
||||
"update_available": latest_version is not None,
|
||||
"current_version": __version__,
|
||||
|
||||
@@ -75,7 +75,7 @@ class SessionEntry:
|
||||
"""
|
||||
return self.lock.locked()
|
||||
|
||||
def summary(self) -> Dict[str, Any]:
|
||||
def summary(self, include_actions: bool = True) -> Dict[str, Any]:
|
||||
"""Dashboard view of the session: no service instance, no raw owner key."""
|
||||
from unshackle.core.api.stats import mask_key
|
||||
|
||||
@@ -100,7 +100,7 @@ class SessionEntry:
|
||||
"server_cdm_max_height": self.server_cdm_max_height,
|
||||
"log_seq": self.log_buffer.last_seq if self.log_buffer else 0,
|
||||
"client": self.client,
|
||||
"actions": list(self.actions),
|
||||
**({"actions": list(self.actions)} if include_actions else {}),
|
||||
"created_at": self.created_at.isoformat(),
|
||||
"last_accessed": self.last_accessed.isoformat(),
|
||||
"created_ts": self.created_at.timestamp(),
|
||||
@@ -121,11 +121,10 @@ def _publish(
|
||||
action: str, entry: SessionEntry, reason: Optional[str] = None, action_entry: Optional[Dict[str, Any]] = None
|
||||
) -> None:
|
||||
"""Tell dashboard listeners about a remote session; ``action_entry`` replaces the action log with that one action."""
|
||||
data = {"action": action, **entry.summary()}
|
||||
data = {"action": action, **entry.summary(include_actions=action_entry is None)}
|
||||
if reason:
|
||||
data["reason"] = reason
|
||||
if action_entry is not None:
|
||||
del data["actions"]
|
||||
data["action_entry"] = action_entry
|
||||
bus.publish("session", data)
|
||||
|
||||
@@ -301,9 +300,8 @@ class SessionStore:
|
||||
@classmethod
|
||||
async def remove_cache_dirs(cls, cache_tags: List[Optional[str]]) -> None:
|
||||
"""Remove the cache directories of ended remote sessions on a worker thread, outside the store lock."""
|
||||
for tag in cache_tags:
|
||||
if tag:
|
||||
await asyncio.to_thread(cls.cleanup_cache_dir, tag)
|
||||
if any(cache_tags):
|
||||
await asyncio.to_thread(lambda: [cls.cleanup_cache_dir(tag) for tag in cache_tags])
|
||||
|
||||
@staticmethod
|
||||
def cleanup_cache_dir(cache_tag: Optional[str]) -> None:
|
||||
|
||||
@@ -72,7 +72,6 @@ def mask_key(key: Optional[str]) -> str:
|
||||
return key[:4] + "…"
|
||||
|
||||
|
||||
@lru_cache(maxsize=1024)
|
||||
def key_id(key: Optional[str]) -> str:
|
||||
"""A stable id for an API key. A hash prefix, so two unnamed keys never collide the way
|
||||
``mask_key`` does, and the id carries no key material."""
|
||||
|
||||
Reference in New Issue
Block a user