From 4c611c26d706e03f13390085b815b8b2c297f480 Mon Sep 17 00:00:00 2001 From: IlyaKasiutin Date: Sun, 26 Nov 2023 15:59:22 +0300 Subject: [PATCH 1/5] add client --- client/client.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 client/client.py diff --git a/client/client.py b/client/client.py new file mode 100644 index 0000000..31d2a0f --- /dev/null +++ b/client/client.py @@ -0,0 +1,32 @@ +import http.client +from http.client import HTTPConnection +from http import HTTPStatus +import logging + + +logging.basicConfig(level=logging.DEBUG) + + +class Client: + def __init__(self): + self.connection = None + + def set_connection(self, host, port=None): + self.connection = HTTPConnection(host, port) + self.__check_connection() + + def __check_connection(self): + self.connection.request("GET", "/") + response = self.connection.getresponse() + response.read() + if response.status == 200: + logging.debug("Connected successfully") + else: + logging.warning(f"Status: {response.status}, reason: {response.reason}") + + def request(self, method: str, url: str, body=None, headers: dict = {}) -> None: + self.connection.request(method, url, body, headers) + logging.debug(f"Request sent: {method}, {url}") + + def get_response(self) -> http.client.HTTPResponse: + return self.connection.getresponse() From 2974dc04d69fa43353bb70673038fd1e8baa3f94 Mon Sep 17 00:00:00 2001 From: IlyaKasiutin Date: Sun, 26 Nov 2023 16:01:12 +0300 Subject: [PATCH 2/5] add lru cache --- cache/lru_cache.py | 105 +++++++++++++++++++++++++++++++++++++++++++++ cache/singleton.py | 5 +++ 2 files changed, 110 insertions(+) create mode 100644 cache/lru_cache.py create mode 100644 cache/singleton.py diff --git a/cache/lru_cache.py b/cache/lru_cache.py new file mode 100644 index 0000000..1e675ea --- /dev/null +++ b/cache/lru_cache.py @@ -0,0 +1,105 @@ +"""LRU Cache with logging options""" + + +import logging + +from singleton import Singleton + + +logger = logging.getLogger("LRUCache") +logger.setLevel(logging.DEBUG) +handler = logging.FileHandler("cache.log", 'w') +formatter = logging.Formatter("%(asctime)s\t%(levelname)s\t%(name)s\t%(message)s") +handler.setFormatter(formatter) +logger.addHandler(handler) + + +class LRUCache(Singleton): + """LRU Cache implementation""" + def __init__(self, limit=42): + self.limit = limit + self.cache = {} + self.head = None + self.tail = None + logger.debug("New LRUCache instance created") + + def get(self, key): + """Get value by key""" + if key not in self.cache: + logger.info("Got key='%s' which is not in cache", key) + return None + + node = self.cache[key] + self.__move_to_front(node) + logger.debug("Got key='%s' from cache", key) + return node.value + + def set(self, key, value): + """Set key-value""" + if key in self.cache: + node = self.cache[key] + node.value = value + logger.debug("Updated key='%s'", key) + self.__move_to_front(node) + else: + node = Node(key, value) + self.cache[key] = node + logger.debug("Added key='%s' to cache", key) + self.__add_to_front(node) + + if len(self.cache) > self.limit: + logger.info("Removing last key...") + self.__remove_last() + + def __add_to_front(self, node): + if not self.head: + self.head = node + self.tail = node + else: + node.next = self.head + self.head.prev = node + self.head = node + + def __remove_last(self): + if not self.tail: + return + + last_key = self.tail.key + last_elem = self.cache.pop(self.tail.key).value + logger.debug("Removed key='%s', value='%s'", last_key, last_elem) + + if self.head == self.tail: + self.head = None + self.tail = None + else: + self.tail = self.tail.prev + self.tail.next = None + + def __move_to_front(self, node): + if node == self.head: + return + + if node == self.tail: + self.tail = node.prev + self.tail.next = None + else: + node.prev.next = node.next + node.next.prev = node.prev + + node.prev = None + node.next = self.head + self.head.prev = node + self.head = node + + logger.info("Moved to front key='%s', value='%s'", self.head.key, self.head.value) + + +class Node: + """Subclass for LRUCache""" + def __init__(self, key, value): + self.key = key + self.value = value + self.prev = None + self.next = None + + logger.debug("New Node instance created") diff --git a/cache/singleton.py b/cache/singleton.py new file mode 100644 index 0000000..e786de3 --- /dev/null +++ b/cache/singleton.py @@ -0,0 +1,5 @@ +class Singleton(object): + def __new__(cls): + if not hasattr(cls, 'instance'): + cls.instance = super(Singleton, cls).__new__(cls) + return cls.instance From a988034550917c59529a791e1774c7ee2bb916be Mon Sep 17 00:00:00 2001 From: IlyaKasiutin Date: Sun, 26 Nov 2023 16:03:33 +0300 Subject: [PATCH 3/5] add cache --- cache/ttl_cache.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 cache/ttl_cache.py diff --git a/cache/ttl_cache.py b/cache/ttl_cache.py new file mode 100644 index 0000000..a599348 --- /dev/null +++ b/cache/ttl_cache.py @@ -0,0 +1,14 @@ +from lru_cache import LRUCache + +# not working +def ttl_cache(ttl, limit): + lru = LRUCache(limit) + + def decorator(func): + def inner(*args, **kwargs): + if [args, kwargs] in lru.cache: + return lru.get([args, kwargs]) + res = func(*args, **kwargs) + return res + return inner + return decorator From d03c5f4237e03ff1f7d83d028d13fa1a433007b2 Mon Sep 17 00:00:00 2001 From: IlyaKasiutin Date: Sun, 26 Nov 2023 16:46:37 +0300 Subject: [PATCH 4/5] add lru decorator --- cache/lru_decorator.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 cache/lru_decorator.py diff --git a/cache/lru_decorator.py b/cache/lru_decorator.py new file mode 100644 index 0000000..82fd28f --- /dev/null +++ b/cache/lru_decorator.py @@ -0,0 +1,16 @@ +from lru_cache import LRUCache + + +def lru_cache(limit): + lru = LRUCache(limit) + + def decorator(func): + def inner(*args, **kwargs): + key = str(args, kwargs) + if key in lru.cache: + return lru.get(key) + res = func(*args, **kwargs) + lru.set(key, res) + return res + return inner + return decorator From c2d361e7c588ec81aa1ea010c9329811818a6af6 Mon Sep 17 00:00:00 2001 From: IlyaKasiutin Date: Sun, 26 Nov 2023 17:04:05 +0300 Subject: [PATCH 5/5] working lru decorator --- cache/lru_decorator.py | 4 +++- cache/singleton.py | 2 +- cache/ttl_cache.py | 11 ++++++----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/cache/lru_decorator.py b/cache/lru_decorator.py index 82fd28f..1364d95 100644 --- a/cache/lru_decorator.py +++ b/cache/lru_decorator.py @@ -6,11 +6,13 @@ def lru_cache(limit): def decorator(func): def inner(*args, **kwargs): - key = str(args, kwargs) + key = func if key in lru.cache: return lru.get(key) res = func(*args, **kwargs) lru.set(key, res) return res + return inner + return decorator diff --git a/cache/singleton.py b/cache/singleton.py index e786de3..c9a639f 100644 --- a/cache/singleton.py +++ b/cache/singleton.py @@ -1,5 +1,5 @@ class Singleton(object): - def __new__(cls): + def __new__(cls, *args): if not hasattr(cls, 'instance'): cls.instance = super(Singleton, cls).__new__(cls) return cls.instance diff --git a/cache/ttl_cache.py b/cache/ttl_cache.py index a599348..cbfab2b 100644 --- a/cache/ttl_cache.py +++ b/cache/ttl_cache.py @@ -1,14 +1,15 @@ from lru_cache import LRUCache -# not working + def ttl_cache(ttl, limit): lru = LRUCache(limit) def decorator(func): - def inner(*args, **kwargs): - if [args, kwargs] in lru.cache: - return lru.get([args, kwargs]) - res = func(*args, **kwargs) + def inner(path, method): + key = str(path) + str(method) + if key in lru.cache: + return lru.get(key) + res = func(path, method) return res return inner return decorator