File size: 3,571 Bytes
7a88b43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import pickle
from logging import Logger

from pymemcache.client.base import Client

from app.core.config import settings
from app.core.exceptions.base_exception import (
    ConnectionException,
    CouldNotEditMemcache,
    KeyNotFoundException,
)


class Cache:
    """
    A generic cache class for interacting with Memcached.
    """

    def __init__(self, logger: Logger) -> None:
        """
        Initialize the cache connection.

        :param logger: Logger instance for logging operations
        """

        # Load Memcache config from .env
        self.host = settings.CACHE_HOST
        self.port = settings.CACHE_HOST
        self.default_ttl = settings.CACHE_TTL

        self.client = self._initialize_connection()
        self.logger = logger

    def _initialize_connection(self):
        """
        Establish a connection to the Memcached server.

        :return: Client instance
        :raises ConnectionException: If the connection cannot be established
        """
        client = Client((self.host, self.port))
        if client:
            self.logger.info(f"Connected to Memcached at {self.host}: {self.port}")
            return client
        else:
            raise ConnectionException("Could not connect to Memcached server.")

    def add(self, key: str, value: dict):
        """
        Add an item to the cache.

        :param key: Cache key
        :param value: Value to store (serialized using pickle)
        :raises CouldNotEditMemcache: If the item could not be added
        """
        serialized_value = pickle.dumps(value)
        res = self.client.add(key, serialized_value, expire=self.default_ttl)
        if not res:
            raise CouldNotEditMemcache(f"Could not add key {key} to cache.")
        self.logger.info(f"Added {key} to cache.")

    def get(self, key: str):
        """
        Retrieve an item from the cache.

        :param key: Cache key
        :return: Deserialized value
        :raises KeyNotFoundException: If the key is not found in the cache
        """
        byte_string = self.get_raw(key)
        return pickle.loads(byte_string)

    def get_raw(self, key: str):
        """
        Retrieve the raw byte string from the cache.

        :param key: Cache key
        :return: Raw byte string
        :raises KeyNotFoundException: If the key is not found in the cache
        """
        byte_string = self.client.get(key)
        if not byte_string:
            raise KeyNotFoundException(f"Key {key} not found in cache.")  # noqa: E713
        return byte_string

    def delete(self, key: str):
        """
        Delete an item from the cache.

        :param key: Cache key
        :return: Result of the delete operation
        :raises CouldNotEditMemcache: If the item could not be deleted
        """
        res = self.client.delete(key)
        if not res:
            raise CouldNotEditMemcache(f"Could not delete key {key} from cache.")
        self.logger.info(f"Deleted {key} from cache.")
        return res

    def update(self, key: str, value: dict):
        """
        Update an item in the cache.

        :param key: Cache key
        :param value: New value to store (serialized using pickle)
        :raises CouldNotEditMemcache: If the item could not be updated
        """
        serialized_value = pickle.dumps(value)
        res = self.client.set(key, serialized_value, expire=self.default_ttl)
        if not res:
            raise CouldNotEditMemcache(f"Could not update key {key} in cache.")
        self.logger.info(f"Updated {key} in cache.")