diff --git a/classes/cache/holo_cache_memcached.py b/classes/cache/holo_cache_memcached.py index a764d24..fe53e65 100644 --- a/classes/cache/holo_cache_memcached.py +++ b/classes/cache/holo_cache_memcached.py @@ -2,10 +2,9 @@ import logging from logging import Logger from typing import Dict, Any -from bson import ObjectId from pymemcache import Client -from ujson import dumps, loads +from modules.cache_utils import string_to_json, json_to_string from . import HoloCache logger: Logger = logging.getLogger(__name__) @@ -17,6 +16,8 @@ class HoloCacheMemcached(HoloCache): def __init__(self, client: Client): self.client = client + logger.info("Initialized Memcached for caching") + @classmethod def from_config(cls, engine_config: Dict[str, Any]) -> "HoloCacheMemcached": if "uri" not in engine_config: @@ -39,7 +40,7 @@ class HoloCacheMemcached(HoloCache): logger.error("Could not get json cache key '%s' due to: %s", key, exc) return None - return None if result is None else self._string_to_json(result) + return None if result is None else string_to_json(result) def get_string(self, key: str) -> str | None: try: @@ -56,13 +57,13 @@ class HoloCacheMemcached(HoloCache): logger.error("Could not get string cache key '%s' due to: %s", key, exc) return None + # TODO Implement binary deserialization def get_object(self, key: str) -> Any | None: - # TODO Implement binary deserialization raise NotImplementedError() def set_json(self, key: str, value: Any) -> None: try: - self.client.set(key, self._json_to_string(value)) + self.client.set(key, json_to_string(value)) logger.debug("Set json cache key '%s'", key) except Exception as exc: logger.error("Could not set json cache key '%s' due to: %s", key, exc) @@ -76,8 +77,8 @@ class HoloCacheMemcached(HoloCache): logger.error("Could not set string cache key '%s' due to: %s", key, exc) return None + # TODO Implement binary serialization def set_object(self, key: str, value: Any) -> None: - # TODO Implement binary serialization raise NotImplementedError() def delete(self, key: str) -> None: @@ -86,21 +87,3 @@ class HoloCacheMemcached(HoloCache): logger.debug("Deleted cache key '%s'", key) except Exception as exc: logger.error("Could not delete cache key '%s' due to: %s", key, exc) - - @staticmethod - def _json_to_string(json_object: Any) -> str: - if isinstance(json_object, dict) and "_id" in json_object: - json_object["_id"] = str(json_object["_id"]) - - return dumps( - json_object, ensure_ascii=False, indent=0, escape_forward_slashes=False - ) - - @staticmethod - def _string_to_json(json_string: str) -> Any: - json_object: Any = loads(json_string) - - if isinstance(json_object, dict) and "_id" in json_object: - json_object["_id"] = ObjectId(json_object["_id"]) - - return json_object diff --git a/classes/cache/holo_cache_redis.py b/classes/cache/holo_cache_redis.py index a22a9aa..5b30bb5 100644 --- a/classes/cache/holo_cache_redis.py +++ b/classes/cache/holo_cache_redis.py @@ -1,34 +1,91 @@ -from typing import Dict, Any +import logging +from logging import Logger +from typing import Dict, Any, List from redis import Redis from classes.cache import HoloCache +from modules.cache_utils import string_to_json, json_to_string + +logger: Logger = logging.getLogger(__name__) class HoloCacheRedis(HoloCache): client: Redis + def __init__(self, client: Redis): + self.client = client + + logger.info("Initialized Redis for caching") + @classmethod def from_config(cls, engine_config: Dict[str, Any]) -> Any: - raise NotImplementedError() + if "uri" not in engine_config: + raise KeyError( + "Cache configuration is invalid. Please check if all keys are set (engine: memcached)" + ) + + uri_split: List[str] = engine_config["uri"].split(":") + + return cls(Redis(host=uri_split[0], port=int(uri_split[1]))) def get_json(self, key: str) -> Any | None: - raise NotImplementedError() + try: + result: Any | None = self.client.get(key) + + logger.debug( + "Got json cache key '%s'%s", + key, + "" if result is not None else " (not found)", + ) + except Exception as exc: + logger.error("Could not get json cache key '%s' due to: %s", key, exc) + return None + + return None if result is None else string_to_json(result) def get_string(self, key: str) -> str | None: - raise NotImplementedError() + try: + result: str | None = self.client.get(key) + logger.debug( + "Got string cache key '%s'%s", + key, + "" if result is not None else " (not found)", + ) + + return result + except Exception as exc: + logger.error("Could not get string cache key '%s' due to: %s", key, exc) + return None + + # TODO Implement binary deserialization def get_object(self, key: str) -> Any | None: raise NotImplementedError() def set_json(self, key: str, value: Any) -> None: - raise NotImplementedError() + try: + self.client.set(key, json_to_string(value)) + logger.debug("Set json cache key '%s'", key) + except Exception as exc: + logger.error("Could not set json cache key '%s' due to: %s", key, exc) + return None def set_string(self, key: str, value: str) -> None: - raise NotImplementedError() + try: + self.client.set(key, value) + logger.debug("Set string cache key '%s'", key) + except Exception as exc: + logger.error("Could not set string cache key '%s' due to: %s", key, exc) + return None + # TODO Implement binary serialization def set_object(self, key: str, value: Any) -> None: raise NotImplementedError() def delete(self, key: str) -> None: - raise NotImplementedError() + try: + self.client.delete(key) + logger.debug("Deleted cache key '%s'", key) + except Exception as exc: + logger.error("Could not delete cache key '%s' due to: %s", key, exc) diff --git a/classes/holo_bot.py b/classes/holo_bot.py index 3b8aa4b..26310dc 100644 --- a/classes/holo_bot.py +++ b/classes/holo_bot.py @@ -15,6 +15,7 @@ class HoloBot(PycordBot): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self._set_cache_engine() def _set_cache_engine(self) -> None: if "cache" in self.config and self.config["cache"]["type"] is not None: diff --git a/modules/cache_utils.py b/modules/cache_utils.py index 02d01fb..85aa629 100644 --- a/modules/cache_utils.py +++ b/modules/cache_utils.py @@ -1,5 +1,9 @@ +from copy import deepcopy from typing import Dict, Any, Literal +from bson import ObjectId +from ujson import dumps, loads + from classes.cache.holo_cache_memcached import HoloCacheMemcached from classes.cache.holo_cache_redis import HoloCacheRedis @@ -27,3 +31,23 @@ def create_cache_client( raise KeyError( f"Cache implementation for the engine '{engine}' is not present." ) + + +def json_to_string(json_object: Any) -> str: + json_object_copy: Any = deepcopy(json_object) + + if isinstance(json_object_copy, dict) and "_id" in json_object_copy: + json_object_copy["_id"] = str(json_object_copy["_id"]) + + return dumps( + json_object_copy, ensure_ascii=False, indent=0, escape_forward_slashes=False + ) + + +def string_to_json(json_string: str) -> Any: + json_object: Any = loads(json_string) + + if "_id" in json_object: + json_object["_id"] = ObjectId(json_object["_id"]) + + return json_object