123 lines
2.1 KiB
Python
123 lines
2.1 KiB
Python
'''Simple caches that uses ordered dicts'''
|
|
|
|
import re
|
|
|
|
from datetime import datetime
|
|
from collections import OrderedDict
|
|
|
|
from .misc import DotDict
|
|
|
|
|
|
def parse_ttl(ttl):
|
|
if not ttl:
|
|
return 0
|
|
|
|
if type(ttl) == int:
|
|
return ttl * 60
|
|
|
|
m = re.match(r'^(\d+)([smhdw]?)$', ttl)
|
|
|
|
if not m:
|
|
raise ValueError(f'Invalid TTL length: {ttl}')
|
|
|
|
amount = m.group(1)
|
|
unit = m.group(2)
|
|
|
|
if not unit:
|
|
raise ValueError('Missing numerical length in TTL')
|
|
|
|
units = {
|
|
's': 1,
|
|
'm': 60,
|
|
'h': 60 * 60,
|
|
'd': 24 * 60 * 60,
|
|
'w': 7 * 24 * 60 * 60
|
|
}
|
|
|
|
multiplier = units.get(unit)
|
|
|
|
if not multiplier:
|
|
raise ValueError(f'Invalid time unit: {unit}')
|
|
|
|
return multiplier * int(amount)
|
|
|
|
|
|
class BaseCache(OrderedDict):
|
|
def __init__(self, maxsize=1024, ttl=None):
|
|
self.ttl = parse_ttl(ttl)
|
|
self.maxsize = maxsize
|
|
self.set = self.store
|
|
|
|
|
|
def __str__(self):
|
|
data = ', '.join([f'{k}="{v["data"]}"' for k,v in self.items()])
|
|
return f'BaseCache({data})'
|
|
|
|
|
|
def get(self, key):
|
|
while len(self) >= self.maxsize and self.maxsize != 0:
|
|
self.popitem(last=False)
|
|
|
|
item = DotDict.get(self, key)
|
|
|
|
if not item:
|
|
return
|
|
|
|
if self.ttl > 0:
|
|
timestamp = int(datetime.timestamp(datetime.now()))
|
|
|
|
if timestamp >= self[key].timestamp:
|
|
del self[key]
|
|
return
|
|
|
|
self[key].timestamp = timestamp + self.ttl
|
|
|
|
self.move_to_end(key)
|
|
return item['data']
|
|
|
|
|
|
def remove(self, key):
|
|
if self.get(key):
|
|
del self[key]
|
|
|
|
|
|
def store(self, key, value):
|
|
if not self.get(key):
|
|
self[key] = DotDict()
|
|
|
|
self[key].data = value
|
|
|
|
if self.ttl:
|
|
timestamp = int(datetime.timestamp(datetime.now()))
|
|
self[key].timestamp = timestamp + self.ttl
|
|
|
|
self.move_to_end(key)
|
|
|
|
|
|
def fetch(self, key):
|
|
item = self.get(key)
|
|
timestamp = int(datetime.timestamp(datetime.now()))
|
|
|
|
if not item:
|
|
return
|
|
|
|
if self.ttl:
|
|
if timestamp >= self[key].timestamp:
|
|
del self[key]
|
|
return
|
|
|
|
self[key]['timestamp'] = timestamp + self.ttl
|
|
|
|
self.move_to_end(key)
|
|
return self[key].data
|
|
|
|
|
|
class TTLCache(BaseCache):
|
|
def __init__(self, maxsize=1024, ttl='1h'):
|
|
super().__init__(maxsize, ttl)
|
|
|
|
|
|
class LRUCache(BaseCache):
|
|
def __init__(self, maxsize=1024):
|
|
super().__init__(maxsize)
|