forked from Hay1tsme/artemis
Begin the process of transitioning from megaime
This commit is contained in:
65
core/data/cache.py
Normal file
65
core/data/cache.py
Normal file
@ -0,0 +1,65 @@
|
||||
|
||||
from typing import Any, Callable
|
||||
from functools import wraps
|
||||
import hashlib
|
||||
import pickle
|
||||
import logging
|
||||
from core.config import CoreConfig
|
||||
|
||||
cfg:CoreConfig = None # type: ignore
|
||||
# Make memcache optional
|
||||
try:
|
||||
import pylibmc # type: ignore
|
||||
has_mc = True
|
||||
except ModuleNotFoundError:
|
||||
has_mc = False
|
||||
|
||||
def cached(lifetime: int=10, extra_key: Any=None) -> Callable:
|
||||
def _cached(func: Callable) -> Callable:
|
||||
if has_mc:
|
||||
hostname = "127.0.0.1"
|
||||
if cfg:
|
||||
hostname = cfg.database.memcached_host
|
||||
memcache = pylibmc.Client([hostname], binary=True)
|
||||
memcache.behaviors = {"tcp_nodelay": True, "ketama": True}
|
||||
|
||||
@wraps(func)
|
||||
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
||||
if lifetime is not None:
|
||||
|
||||
# Hash function args
|
||||
items = kwargs.items()
|
||||
hashable_args = (args[1:], sorted(list(items)))
|
||||
args_key = hashlib.md5(pickle.dumps(hashable_args)).hexdigest()
|
||||
|
||||
# Generate unique cache key
|
||||
cache_key = f'{func.__module__}-{func.__name__}-{args_key}-{extra_key() if hasattr(extra_key, "__call__") else extra_key}'
|
||||
|
||||
# Return cached version if allowed and available
|
||||
try:
|
||||
result = memcache.get(cache_key)
|
||||
except pylibmc.Error as e:
|
||||
logging.getLogger("database").error(f"Memcache failed: {e}")
|
||||
result = None
|
||||
|
||||
if result is not None:
|
||||
logging.getLogger("database").debug(f"Cache hit: {result}")
|
||||
return result
|
||||
|
||||
# Generate output
|
||||
result = func(*args, **kwargs)
|
||||
|
||||
# Cache output if allowed
|
||||
if lifetime is not None and result is not None:
|
||||
logging.getLogger("database").debug(f"Setting cache: {result}")
|
||||
memcache.set(cache_key, result, lifetime)
|
||||
|
||||
return result
|
||||
else:
|
||||
@wraps(func)
|
||||
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
return _cached
|
Reference in New Issue
Block a user