60 lines
1.9 KiB
Python
60 lines
1.9 KiB
Python
from server.GameBoard import GameBoard
|
|
import inspect
|
|
import pickle
|
|
|
|
class RedisGameBoardStore:
|
|
def __init__(self, redis_url:str="redis://localhost:6379/0", key_prefix:str="snake:gameboard", ttl_seconds:int=900, **kwargs):
|
|
self.redis_url = redis_url
|
|
self.key_prefix = key_prefix
|
|
self.ttl_seconds = max(60, int(ttl_seconds))
|
|
self._redis = None
|
|
|
|
async def _get_redis(self):
|
|
if self._redis is not None:
|
|
return self._redis
|
|
|
|
try:
|
|
import redis.asyncio as aioredis # type: ignore[import-not-found]
|
|
except ImportError as error: # pragma: no cover
|
|
raise RuntimeError("Redis backend selected but 'redis' package with asyncio support is not installed") from error
|
|
|
|
self._redis = aioredis.from_url(self.redis_url)
|
|
return self._redis
|
|
|
|
def _key(self, game_id:str) -> str:
|
|
return f"{self.key_prefix}:{game_id}"
|
|
|
|
async def save(self, game_id:str, game_board:GameBoard) -> None:
|
|
redis = await self._get_redis()
|
|
payload = pickle.dumps(game_board, protocol=pickle.HIGHEST_PROTOCOL)
|
|
await redis.set(self._key(game_id), payload, ex=self.ttl_seconds)
|
|
|
|
async def load(self, game_id:str):
|
|
redis = await self._get_redis()
|
|
payload = await redis.get(self._key(game_id))
|
|
if payload is None:
|
|
return None
|
|
return pickle.loads(payload)
|
|
|
|
async def delete(self, game_id:str) -> None:
|
|
redis = await self._get_redis()
|
|
await redis.delete(self._key(game_id))
|
|
|
|
async def close(self) -> None:
|
|
if self._redis is None:
|
|
return
|
|
|
|
aclose_method = getattr(self._redis, "aclose", None)
|
|
if callable(aclose_method):
|
|
maybe_result = aclose_method()
|
|
if inspect.isawaitable(maybe_result):
|
|
await maybe_result
|
|
else:
|
|
close_method = getattr(self._redis, "close", None)
|
|
if callable(close_method):
|
|
close_result = close_method()
|
|
if inspect.isawaitable(close_result):
|
|
await close_result
|
|
|
|
self._redis = None
|