create MemoryGameBoardStore Class and rework Building of Game Board Storage
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
from server.GameBoard import GameBoard
|
||||
|
||||
class MemoryGameBoardStore:
|
||||
def __init__(self, **kwargs):
|
||||
self._state:dict[str, object] = {}
|
||||
|
||||
async def save(self, game_id:str, game_board:GameBoard) -> None:
|
||||
self._state[game_id] = game_board
|
||||
|
||||
async def load(self, game_id:str):
|
||||
return self._state.get(game_id)
|
||||
|
||||
async def delete(self, game_id:str) -> None:
|
||||
self._state.pop(game_id, None)
|
||||
|
||||
async def close(self) -> None:
|
||||
return None
|
||||
@@ -0,0 +1,53 @@
|
||||
from server.GameBoard import GameBoard
|
||||
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 aioredis # type: ignore[import-not-found]
|
||||
except ImportError as error: # pragma: no cover
|
||||
raise RuntimeError("Redis backend selected but 'aioredis' package 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
|
||||
|
||||
if hasattr(self._redis, "aclose"):
|
||||
await self._redis.aclose()
|
||||
elif hasattr(self._redis, "close"):
|
||||
close_result = self._redis.close()
|
||||
if close_result is not None:
|
||||
await close_result
|
||||
|
||||
self._redis = None
|
||||
@@ -0,0 +1,10 @@
|
||||
from server.game_board_stats.MemoryGameBoardStore import MemoryGameBoardStore
|
||||
from server.game_board_stats.RedisGameBoardStore import RedisGameBoardStore
|
||||
|
||||
class GameBoardStoreBuilder:
|
||||
@classmethod
|
||||
def build(self, backend:str="memory", **kwargs) -> MemoryGameBoardStore|RedisGameBoardStore:
|
||||
selected = (backend or "memory").strip().lower()
|
||||
if selected == "redis":
|
||||
return RedisGameBoardStore(**kwargs)
|
||||
return MemoryGameBoardStore(**kwargs)
|
||||
Reference in New Issue
Block a user