Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client #3

Open
wants to merge 5 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions cache/lru_cache.py
Original file line number Diff line number Diff line change
@@ -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")
18 changes: 18 additions & 0 deletions cache/lru_decorator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from lru_cache import LRUCache


def lru_cache(limit):
lru = LRUCache(limit)

def decorator(func):
def inner(*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
5 changes: 5 additions & 0 deletions cache/singleton.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Singleton(object):
def __new__(cls, *args):
if not hasattr(cls, 'instance'):
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance
15 changes: 15 additions & 0 deletions cache/ttl_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from lru_cache import LRUCache


def ttl_cache(ttl, limit):
lru = LRUCache(limit)

def decorator(func):
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
32 changes: 32 additions & 0 deletions client/client.py
Original file line number Diff line number Diff line change
@@ -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()