82 lines
2.4 KiB
Python
82 lines
2.4 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any, Awaitable, Callable, Optional
|
|
|
|
from bot.infra.redis import cache_delete, redis_key
|
|
from bot.utils.ttl_cache import AsyncTTLCache
|
|
from config.settings import Settings
|
|
|
|
_WEBAPP_USER_PAYLOAD_CACHES: dict[tuple[int, str, int], AsyncTTLCache] = {}
|
|
|
|
|
|
def _webapp_user_payload_cache(
|
|
settings: Settings,
|
|
namespace: str,
|
|
ttl_seconds: int,
|
|
) -> Optional[AsyncTTLCache]:
|
|
ttl = max(0, int(ttl_seconds or 0))
|
|
if ttl <= 0:
|
|
return None
|
|
cache_key = (id(settings), namespace, ttl)
|
|
cache = _WEBAPP_USER_PAYLOAD_CACHES.get(cache_key)
|
|
if cache is None:
|
|
cache = AsyncTTLCache(
|
|
ttl_seconds=ttl,
|
|
settings=settings,
|
|
namespace=f"webapp:{namespace}",
|
|
)
|
|
_WEBAPP_USER_PAYLOAD_CACHES[cache_key] = cache
|
|
return cache
|
|
|
|
|
|
async def webapp_cached_user_payload(
|
|
settings: Settings,
|
|
namespace: str,
|
|
user_id: int,
|
|
ttl_seconds: int,
|
|
loader: Callable[[], Awaitable[Any]],
|
|
) -> Any:
|
|
cache = _webapp_user_payload_cache(settings, namespace, ttl_seconds)
|
|
if cache is None:
|
|
return await loader()
|
|
return await cache.get_or_load(str(int(user_id)), loader)
|
|
|
|
|
|
def invalidate_local_webapp_user_payload(
|
|
settings: Settings,
|
|
namespace: str,
|
|
user_id: int,
|
|
) -> None:
|
|
key = str(int(user_id))
|
|
for (settings_id, cache_namespace, _ttl), cache in tuple(
|
|
_WEBAPP_USER_PAYLOAD_CACHES.items()
|
|
):
|
|
if settings_id == id(settings) and cache_namespace == namespace:
|
|
cache.invalidate(key)
|
|
|
|
|
|
async def invalidate_webapp_user_caches(
|
|
settings: Settings,
|
|
*user_ids: Optional[int],
|
|
include_devices: bool = False,
|
|
) -> None:
|
|
keys: list[str] = []
|
|
seen: set[int] = set()
|
|
for raw_user_id in user_ids:
|
|
if raw_user_id is None:
|
|
continue
|
|
try:
|
|
user_id = int(raw_user_id)
|
|
except (TypeError, ValueError):
|
|
continue
|
|
if user_id in seen:
|
|
continue
|
|
seen.add(user_id)
|
|
keys.append(redis_key(settings, "cache", "webapp", "me", user_id))
|
|
invalidate_local_webapp_user_payload(settings, "me", user_id)
|
|
if include_devices:
|
|
keys.append(redis_key(settings, "cache", "webapp", "devices", user_id))
|
|
invalidate_local_webapp_user_payload(settings, "devices", user_id)
|
|
if keys:
|
|
await cache_delete(settings, *keys)
|