2020-10-08 15:10:34 +08:00
|
|
|
import time
|
2020-11-10 10:34:52 +08:00
|
|
|
from asyncio import Lock
|
2020-10-08 15:10:34 +08:00
|
|
|
from dataclasses import dataclass
|
|
|
|
|
from typing import Dict, Optional, Tuple
|
|
|
|
|
|
|
|
|
|
from fastapi_cache.backends import Backend
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
class Value:
|
2023-05-09 18:17:28 +01:00
|
|
|
data: bytes
|
2020-10-08 15:10:34 +08:00
|
|
|
ttl_ts: int
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InMemoryBackend(Backend):
|
|
|
|
|
_store: Dict[str, Value] = {}
|
|
|
|
|
_lock = Lock()
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def _now(self) -> int:
|
|
|
|
|
return int(time.time())
|
|
|
|
|
|
2022-11-03 15:49:58 +04:00
|
|
|
def _get(self, key: str) -> Optional[Value]:
|
2020-10-08 15:10:34 +08:00
|
|
|
v = self._store.get(key)
|
|
|
|
|
if v:
|
|
|
|
|
if v.ttl_ts < self._now:
|
|
|
|
|
del self._store[key]
|
|
|
|
|
else:
|
|
|
|
|
return v
|
2022-10-22 20:59:37 +04:00
|
|
|
return None
|
2020-10-08 15:10:34 +08:00
|
|
|
|
2023-05-09 18:17:28 +01:00
|
|
|
async def get_with_ttl(self, key: str) -> Tuple[int, Optional[bytes]]:
|
2020-11-10 10:34:52 +08:00
|
|
|
async with self._lock:
|
2020-10-08 15:10:34 +08:00
|
|
|
v = self._get(key)
|
|
|
|
|
if v:
|
|
|
|
|
return v.ttl_ts - self._now, v.data
|
|
|
|
|
return 0, None
|
|
|
|
|
|
2023-05-09 18:17:28 +01:00
|
|
|
async def get(self, key: str) -> Optional[bytes]:
|
2020-11-10 10:34:52 +08:00
|
|
|
async with self._lock:
|
2020-10-08 15:10:34 +08:00
|
|
|
v = self._get(key)
|
|
|
|
|
if v:
|
|
|
|
|
return v.data
|
2022-10-22 20:59:37 +04:00
|
|
|
return None
|
2020-10-08 15:10:34 +08:00
|
|
|
|
2023-05-09 18:17:28 +01:00
|
|
|
async def set(self, key: str, value: bytes, expire: Optional[int] = None) -> None:
|
2020-11-10 10:34:52 +08:00
|
|
|
async with self._lock:
|
2022-04-24 11:19:20 +08:00
|
|
|
self._store[key] = Value(value, self._now + (expire or 0))
|
2020-11-03 18:08:06 +08:00
|
|
|
|
2022-10-22 20:59:37 +04:00
|
|
|
async def clear(self, namespace: Optional[str] = None, key: Optional[str] = None) -> int:
|
2020-11-03 18:08:06 +08:00
|
|
|
count = 0
|
|
|
|
|
if namespace:
|
|
|
|
|
keys = list(self._store.keys())
|
|
|
|
|
for key in keys:
|
|
|
|
|
if key.startswith(namespace):
|
|
|
|
|
del self._store[key]
|
|
|
|
|
count += 1
|
|
|
|
|
elif key:
|
|
|
|
|
del self._store[key]
|
|
|
|
|
count += 1
|
|
|
|
|
return count
|