inmemory.py 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import time
  2. from asyncio import Lock
  3. from dataclasses import dataclass
  4. from typing import Dict, Optional, Tuple
  5. from fastapi_cache.types import Backend
  6. @dataclass
  7. class Value:
  8. data: bytes
  9. ttl_ts: int
  10. class InMemoryBackend(Backend):
  11. _store: Dict[str, Value] = {}
  12. _lock = Lock()
  13. @property
  14. def _now(self) -> int:
  15. return int(time.time())
  16. def _get(self, key: str) -> Optional[Value]:
  17. v = self._store.get(key)
  18. if v:
  19. if v.ttl_ts < self._now:
  20. del self._store[key]
  21. else:
  22. return v
  23. return None
  24. async def get_with_ttl(self, key: str) -> Tuple[int, Optional[bytes]]:
  25. async with self._lock:
  26. v = self._get(key)
  27. if v:
  28. return v.ttl_ts - self._now, v.data
  29. return 0, None
  30. async def get(self, key: str) -> Optional[bytes]:
  31. async with self._lock:
  32. v = self._get(key)
  33. if v:
  34. return v.data
  35. return None
  36. async def set(self, key: str, value: bytes, expire: Optional[int] = None) -> None:
  37. async with self._lock:
  38. self._store[key] = Value(value, self._now + (expire or 0))
  39. async def clear(self, namespace: Optional[str] = None, key: Optional[str] = None) -> int:
  40. count = 0
  41. if namespace:
  42. keys = list(self._store.keys())
  43. for key in keys:
  44. if key.startswith(namespace):
  45. del self._store[key]
  46. count += 1
  47. elif key:
  48. del self._store[key]
  49. count += 1
  50. return count