perf(api): stop rebuilding proxy catalogues, vaults and cdms per request

Cache proxy provider catalogues (10 min), reuse vaults and CDMs across one batch licence call, and cache the health update check, /api/services entries and parsed service config.yaml.
This commit is contained in:
imSp4rky
2026-11-02 14:40:58 -07:00
parent e01204ac13
commit bb081046e2
23 changed files with 316 additions and 163 deletions
+7
View File
@@ -11,6 +11,7 @@ import pytest
from unshackle.core import binaries
from unshackle.core.config import config
from unshackle.core.proxies.proxy import CATALOGUES
from unshackle.core.update_checker import UpdateChecker
# shutdown() blocks until the serve loop polls again, and the 0.5s default is paid by every
@@ -40,6 +41,12 @@ def no_update_check(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(UpdateChecker, "check_for_updates_sync", lambda *args, **kwargs: None)
@pytest.fixture(autouse=True)
def fresh_proxy_catalogues() -> None:
"""Fetch each proxy provider catalogue again, so one test's stub never answers another test."""
CATALOGUES.clear()
@pytest.fixture(autouse=True)
def default_muxing(monkeypatch: pytest.MonkeyPatch) -> None:
"""Mux with the default options, whatever the muxing block of the local unshackle.yaml sets."""
+37
View File
@@ -0,0 +1,37 @@
"""The proxy provider catalogue cache."""
from __future__ import annotations
import pytest
from unshackle.core.proxies import proxy
from unshackle.core.proxies.proxy import cached_catalogue
def test_catalogue_is_fetched_once_until_it_expires(monkeypatch: pytest.MonkeyPatch) -> None:
calls: list[int] = []
@cached_catalogue
def fetch() -> list[dict]:
calls.append(1)
return [{"country": "CA"}]
assert fetch() == fetch() == [{"country": "CA"}]
assert len(calls) == 1
monkeypatch.setattr(proxy, "CATALOGUE_TTL", 0.0)
fetch()
assert len(calls) == 2
def test_empty_catalogue_is_not_kept() -> None:
calls: list[int] = []
@cached_catalogue
def fetch() -> list[dict]:
calls.append(1)
return []
fetch()
fetch()
assert len(calls) == 2
+17
View File
@@ -66,3 +66,20 @@ def test_server_pushes_again_after_one_vault_failed(monkeypatch: pytest.MonkeyPa
handlers.cache_to_vaults({KID.hex: KEY}, "SVC")
handlers.cache_to_vaults({KID.hex: KEY}, "SVC")
assert len(pushes) == 2
def test_one_licence_request_builds_the_server_vaults_once(monkeypatch: pytest.MonkeyPatch) -> None:
builds: list = []
pushes: list = []
def build(name: str) -> Any:
builds.append(name)
return fake_server_vaults(pushes, [FakeVault(False)])
monkeypatch.setattr(handlers, "load_server_vaults", build)
monkeypatch.setattr(handlers, "CACHED_PAIRS", set())
shared: dict = {}
handlers.cache_to_vaults({KID.hex: KEY}, "SVC", shared=shared)
handlers.cache_to_vaults({KID.hex: KEY}, "SVC", shared=shared)
assert len(builds) == 1
assert len(pushes) == 2
+2 -2
View File
@@ -238,7 +238,7 @@ def test_a_lent_device_session_never_licenses_live() -> None:
def test_a_vault_only_miss_raises_the_refusal(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(handlers, "check_vaults", lambda kids, service: None)
monkeypatch.setattr(handlers, "check_vaults", lambda kids, service, **_: None)
monkeypatch.setattr(handlers, "ensure_track_drm", lambda *a, **k: None)
refusal = handlers.live_licence_refusal(SimpleNamespace(server_device=True), object())
with pytest.raises(APIError) as caught:
@@ -257,7 +257,7 @@ def test_a_vault_only_miss_raises_the_refusal(monkeypatch: pytest.MonkeyPatch) -
def test_a_vault_only_hit_needs_no_server_device(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(
handlers, "check_vaults", lambda kids, service: ({SESSION_KID.hex: "k"}, {SESSION_KID.hex: "v"})
handlers, "check_vaults", lambda kids, service, **_: ({SESSION_KID.hex: "k"}, {SESSION_KID.hex: "v"})
)
monkeypatch.setattr(handlers, "ensure_track_drm", lambda *a, **k: None)
monkeypatch.setattr(
@@ -55,7 +55,9 @@ async def _run_batch(monkeypatch, tracks, cdm_type, calls):
async def fake_get_session(session_id, request):
return session
def fake_single(service, title, track, pssh_str, drm_type, request, sources=None, refusal=None, vault_only=False):
def fake_single(
service, title, track, pssh_str, drm_type, request, sources=None, refusal=None, vault_only=False, shared=None
):
calls.append((pssh_str, drm_type))
return {"00" * 16: "key"}
@@ -34,7 +34,7 @@ def patch_server_region(monkeypatch, region):
def patch_providers(monkeypatch, proxy):
"""Give the server one provider that answers every country code with ``proxy``."""
provider = SimpleNamespace(get_proxy=lambda query: proxy)
monkeypatch.setattr(handlers, "initialize_proxy_providers", lambda: [provider])
monkeypatch.setattr(handlers, "initialize_proxy_providers", lambda **_: [provider])
return provider
@@ -101,7 +101,7 @@ def test_provider_country_rejected(monkeypatch):
def test_no_proxy_short_circuits(monkeypatch):
"""no_proxy skips resolution and never loads providers, even with a proxy param set."""
monkeypatch.setattr(handlers, "initialize_proxy_providers", lambda: pytest.fail("providers loaded"))
monkeypatch.setattr(handlers, "initialize_proxy_providers", lambda **_: pytest.fail("providers loaded"))
_, providers = handlers.resolve_handler_proxy(
{"proxy": "us", "no_proxy": True, "client_region": "ca"}, "EXAMPLE", request("proxykey")
)
@@ -154,7 +154,7 @@ def test_user_without_server_proxy_denied(monkeypatch):
def test_no_region_sent_proceeds(monkeypatch):
"""An out-of-date client that reports no region is unknown and never blocked."""
patch_server_region(monkeypatch, "IN")
monkeypatch.setattr(handlers, "initialize_proxy_providers", lambda: [])
monkeypatch.setattr(handlers, "initialize_proxy_providers", lambda **_: [])
assert handlers.resolve_handler_proxy({}, "EXAMPLE", request("plainkey")) == (None, [])
assert handlers.resolve_handler_proxy({}, "EXAMPLE", request("proxykey")) == (None, [])
@@ -241,7 +241,7 @@ class TestDownloadGates:
def test_country_code_passes_when_opted_in(self, monkeypatch):
# The gate must not even try to resolve for an opted-in key: dl resolves at run time,
# exactly as before the gate existed.
monkeypatch.setattr(handlers, "initialize_proxy_providers", lambda: pytest.fail("providers loaded"))
monkeypatch.setattr(handlers, "initialize_proxy_providers", lambda **_: pytest.fail("providers loaded"))
handlers.enforce_download_gates({"service": "EXAMPLE", "proxy": "us"}, request("proxykey"))
def test_region_mismatch_rejected_at_submit(self, monkeypatch):
@@ -388,7 +388,7 @@ def test_local_proxy_uri_refused_without_server_proxy(proxy):
@pytest.mark.parametrize("key", ["proxykey", "adminkey"]) # adminkey has no serve.users entry
def test_local_proxy_uri_allowed_with_server_proxy_or_admin(monkeypatch, key):
monkeypatch.setattr(handlers, "initialize_proxy_providers", lambda: [])
monkeypatch.setattr(handlers, "initialize_proxy_providers", lambda **_: [])
proxy, _ = handlers.resolve_handler_proxy({"proxy": "http://127.0.0.1:8080"}, "EXAMPLE", request(key))
assert proxy == "http://127.0.0.1:8080"
@@ -157,8 +157,8 @@ def widevine_env(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(detect_mod, "is_widevine_cdm", lambda cdm: True)
monkeypatch.setattr(handlers, "ensure_track_drm", lambda track, session=None, init_data=None: None)
monkeypatch.setattr(handlers, "resolve_device_name", lambda *a, **k: "dev")
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name: None)
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name: None)
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name, **_: None)
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name, **_: None)
monkeypatch.setattr(handlers.config, "serve", {"users": {}}, raising=False)
@@ -170,7 +170,7 @@ def playready_env(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(detect_mod, "is_playready_cdm", lambda cdm: True)
monkeypatch.setattr(handlers, "ensure_track_drm", lambda track, session=None, init_data=None: None)
monkeypatch.setattr(handlers, "resolve_device_name", lambda *a, **k: "dev")
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name: None)
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name, **_: None)
monkeypatch.setattr(handlers.config, "serve", {"users": {}}, raising=False)
@@ -59,8 +59,8 @@ def env(monkeypatch):
monkeypatch.setattr(detect_mod, "is_playready_cdm", lambda cdm: True)
monkeypatch.setattr(handlers, "ensure_track_drm", lambda track, session=None, init_data=None: None)
monkeypatch.setattr(handlers, "resolve_device_name", lambda *a, **k: "dev")
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name: None)
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name: None)
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name, **_: None)
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name, **_: None)
monkeypatch.setattr(handlers, "server_cdm_allowed", lambda request, tag: True)
monkeypatch.setattr(handlers, "find_title_for_track", lambda tid, session: SimpleNamespace())
monkeypatch.setattr(handlers.config, "serve", {"users": {}}, raising=False)
@@ -58,8 +58,8 @@ def playready_env(monkeypatch):
monkeypatch.setattr(detect_mod, "is_playready_cdm", lambda cdm: True)
monkeypatch.setattr(handlers, "ensure_track_drm", lambda track, session=None, init_data=None: None)
monkeypatch.setattr(handlers, "resolve_device_name", lambda *a, **k: "dev")
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name: None)
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name: None)
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name, **_: None)
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name, **_: None)
monkeypatch.setattr(handlers.config, "serve", {"users": {}}, raising=False)
@@ -120,7 +120,9 @@ async def test_batch_reports_vault_keys_from_the_init_segment_pssh(monkeypatch):
async def validated(sid, req):
return session
def fake_single(service, title, track, pssh_str, drm_type, request, sources=None, refusal=None, vault_only=False):
def fake_single(
service, title, track, pssh_str, drm_type, request, sources=None, refusal=None, vault_only=False, shared=None
):
if pssh_str == "init":
sources[CDM_KID.hex] = "sqlite"
return {CDM_KID.hex: "v"}
@@ -83,8 +83,8 @@ def server_env(monkeypatch):
monkeypatch.setattr(detect_mod, "is_playready_cdm", lambda cdm: True)
monkeypatch.setattr(handlers, "ensure_track_drm", lambda track, session=None, init_data=None: None)
monkeypatch.setattr(handlers, "resolve_device_name", lambda *a, **k: "dev")
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name: None)
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name: None)
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name, **_: None)
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name, **_: None)
monkeypatch.setattr(handlers, "server_cdm_allowed", lambda request, tag: True)
monkeypatch.setattr(handlers, "find_title_for_track", lambda tid, session: SimpleNamespace())
monkeypatch.setattr(handlers, "detect_cdm_type_for_service", lambda tag, cfg: "playready")
@@ -156,13 +156,13 @@ def single(refusal):
def test_a_vault_hit_is_served_above_the_cap(widevine_env, monkeypatch):
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name: ({"11" * 16: "key"}, {"11" * 16: "sqlite"}))
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name, **_: ({"11" * 16: "key"}, {"11" * 16: "sqlite"}))
refusal = handlers.live_licence_refusal(SimpleNamespace(server_cdm_max_height=1080), video(2160))
assert single(refusal) == {"11" * 16: "key"}
def test_a_vault_miss_raises_the_refusal_before_the_device_loads(widevine_env, monkeypatch):
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name: None)
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name, **_: None)
refusal = handlers.live_licence_refusal(SimpleNamespace(server_cdm_max_height=1080), video(2160))
with pytest.raises(APIError) as ei:
single(refusal)
@@ -406,7 +406,9 @@ def licence_env(monkeypatch):
calls: list = []
vault = {}
def fake_single(service, title, track, pssh_str, drm_type, request, sources=None, refusal=None, vault_only=False):
def fake_single(
service, title, track, pssh_str, drm_type, request, sources=None, refusal=None, vault_only=False, shared=None
):
calls.append((track.id, pssh_str))
if pssh_str in vault:
return dict(vault[pssh_str])
@@ -61,9 +61,9 @@ def playready_env(monkeypatch):
def test_playready_multikey_not_shortcircuited_by_vault(playready_env, monkeypatch):
# The vault holds only the PSSH KID (a stale subset). The old code returned it and skipped
# the license, hiding REAL and OTHER; the fix licenses and returns the whole bundle.
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name: {PSSH_KID.hex: "STALE"})
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name, **_: {PSSH_KID.hex: "STALE"})
cached: dict = {}
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name: cached.update(keys))
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name, **_: cached.update(keys))
keys = handlers.handle_single_server_cdm(
service=SimpleNamespace(),
@@ -99,7 +99,7 @@ def test_widevine_still_uses_vault_shortcut(monkeypatch):
monkeypatch.setattr(drm_mod, "Widevine", _FakeWidevine)
monkeypatch.setattr(handlers, "ensure_track_drm", lambda track, session=None, init_data=None: None)
monkeypatch.setattr(handlers, "resolve_device_name", lambda *a, **k: "dev")
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name: ({kid.hex: "vaultkey"}, {kid.hex: "sqlite"}))
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name, **_: ({kid.hex: "vaultkey"}, {kid.hex: "sqlite"}))
monkeypatch.setattr(handlers.config, "serve", {"users": {}}, raising=False)
sources: dict = {}
@@ -133,7 +133,9 @@ async def test_batch_shares_full_bundle_per_pssh(monkeypatch):
bundle_a = {REAL.hex: "k_real", PSSH_KID.hex: "k_pssh", OTHER.hex: "k_other"}
bundle_b = {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": "k_b"}
def fake_single(service, title, track, pssh_str, drm_type, request, sources=None, refusal=None, vault_only=False):
def fake_single(
service, title, track, pssh_str, drm_type, request, sources=None, refusal=None, vault_only=False, shared=None
):
calls.append(pssh_str)
return dict(bundle_a) if pssh_str == pssh_a else dict(bundle_b)
@@ -56,8 +56,8 @@ def server_env(monkeypatch):
monkeypatch.setattr(detect_mod, "is_playready_cdm", lambda cdm: True)
monkeypatch.setattr(handlers, "ensure_track_drm", lambda track, session=None, init_data=None: None)
monkeypatch.setattr(handlers, "resolve_device_name", lambda *a, **k: "dev")
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name: None)
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name: None)
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name, **_: None)
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name, **_: None)
monkeypatch.setattr(handlers.config, "serve", {"users": {}}, raising=False)
@@ -95,8 +95,8 @@ def env(monkeypatch):
monkeypatch.setattr(detect_mod, "is_widevine_cdm", lambda cdm: cdm.device.startswith("wv"))
monkeypatch.setattr(detect_mod, "is_playready_cdm", lambda cdm: cdm.device.startswith("pr"))
monkeypatch.setattr(handlers, "ensure_track_drm", lambda track, session=None, init_data=None: None)
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name: None)
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name: None)
monkeypatch.setattr(handlers, "check_vaults", lambda kids, name, **_: None)
monkeypatch.setattr(handlers, "cache_to_vaults", lambda keys, name, **_: None)
monkeypatch.setattr(handlers, "server_cdm_allowed", lambda request, tag: True)
monkeypatch.setattr(handlers, "find_title_for_track", lambda tid, session: SimpleNamespace())
monkeypatch.setattr(handlers.config, "serve", {"users": {}}, raising=False)