52 lines
1.5 KiB
Python
52 lines
1.5 KiB
Python
"""In-memory cache OAuth Bearer tokenů PPL CPL API.
|
|
|
|
PPL vydá max. 12 tokenů za minutu a token platí 30 minut — generovat token
|
|
per-request nelze. Cache je klíčovaná SHA-256 hashem přihlašovacích údajů
|
|
(samotné údaje se neukládají) a token se obnovuje s předstihem před expirací.
|
|
|
|
Per-key asyncio.Lock brání souběžnému vyžádání tokenu pro stejné údaje
|
|
(thundering herd při paralelních requestech).
|
|
"""
|
|
import asyncio
|
|
import time
|
|
|
|
from .config import TOKEN_REFRESH_MARGIN_SECONDS
|
|
|
|
# cache_key -> (access_token, expires_at_monotonic)
|
|
_tokens: dict[str, tuple[str, float]] = {}
|
|
_locks: dict[str, asyncio.Lock] = {}
|
|
|
|
|
|
def _lock_for(cache_key: str) -> asyncio.Lock:
|
|
lock = _locks.get(cache_key)
|
|
if lock is None:
|
|
lock = asyncio.Lock()
|
|
_locks[cache_key] = lock
|
|
return lock
|
|
|
|
|
|
def get_cached(cache_key: str) -> str | None:
|
|
entry = _tokens.get(cache_key)
|
|
if entry is None:
|
|
return None
|
|
token, expires_at = entry
|
|
if time.monotonic() >= expires_at:
|
|
_tokens.pop(cache_key, None)
|
|
return None
|
|
return token
|
|
|
|
|
|
def store(cache_key: str, token: str, expires_in_seconds: float) -> None:
|
|
expires_at = time.monotonic() + max(
|
|
expires_in_seconds - TOKEN_REFRESH_MARGIN_SECONDS, 30.0
|
|
)
|
|
_tokens[cache_key] = (token, expires_at)
|
|
|
|
|
|
def invalidate(cache_key: str) -> None:
|
|
_tokens.pop(cache_key, None)
|
|
|
|
|
|
async def acquire_lock(cache_key: str) -> asyncio.Lock:
|
|
return _lock_for(cache_key)
|