mirror of
https://github.com/rachelos/we-mp-rss.git
synced 2026-11-04 01:11:51 +08:00
161 lines
5.5 KiB
Python
161 lines
5.5 KiB
Python
import os
|
|
import hashlib
|
|
import time
|
|
import json
|
|
import pickle
|
|
from typing import Any, Optional, Union
|
|
from functools import wraps
|
|
from core.config import cfg
|
|
|
|
class ViewCache:
|
|
"""视图缓存管理类"""
|
|
|
|
def __init__(self, cache_dir: str = None, default_ttl: int = 1800, enabled: bool = False):
|
|
self.cache_dir = cache_dir or cfg.get("cache.views.dir", "data/cache/views")
|
|
self.default_ttl = default_ttl or cfg.get("cache.views.ttl", 1800) # 默认30分钟
|
|
self.enabled = enabled or cfg.get("cache.views.enabled", False)
|
|
|
|
# 确保缓存目录存在
|
|
if not os.path.exists(self.cache_dir):
|
|
os.makedirs(self.cache_dir, exist_ok=True)
|
|
|
|
def _get_cache_key(self, prefix: str, **kwargs) -> str:
|
|
"""生成缓存键"""
|
|
# 过滤掉不需要包含在缓存键中的参数
|
|
filter_keys = {'request'}
|
|
filtered_kwargs = {k: v for k, v in kwargs.items() if k not in filter_keys}
|
|
|
|
# 将参数转换为可哈希的字符串
|
|
key_data = json.dumps(filtered_kwargs, sort_keys=True, default=str)
|
|
key_hash = hashlib.sha256(key_data.encode('utf-8')).hexdigest()
|
|
return f"{prefix}_{key_hash}"
|
|
|
|
def _get_cache_path(self, cache_key: str) -> str:
|
|
"""获取缓存文件路径"""
|
|
return os.path.join(self.cache_dir, f"{cache_key}.cache")
|
|
|
|
def get(self, prefix: str, ttl: Optional[int] = None, **kwargs) -> Optional[Any]:
|
|
"""获取缓存数据"""
|
|
if not self.enabled:
|
|
return None
|
|
|
|
cache_key = self._get_cache_key(prefix, **kwargs)
|
|
cache_path = self._get_cache_path(cache_key)
|
|
|
|
if not os.path.exists(cache_path):
|
|
return None
|
|
|
|
# 检查缓存是否过期
|
|
ttl = ttl or self.default_ttl
|
|
file_mtime = os.path.getmtime(cache_path)
|
|
if time.time() - file_mtime > ttl:
|
|
# 删除过期缓存
|
|
try:
|
|
os.remove(cache_path)
|
|
except OSError:
|
|
pass
|
|
return None
|
|
|
|
# 读取缓存数据
|
|
try:
|
|
with open(cache_path, 'rb') as f:
|
|
return pickle.load(f)
|
|
except (pickle.PickleError, IOError, EOFError):
|
|
# 缓存文件损坏,删除并返回None
|
|
try:
|
|
os.remove(cache_path)
|
|
except OSError:
|
|
pass
|
|
return None
|
|
|
|
def set(self, prefix: str, data: Any, **kwargs) -> bool:
|
|
"""设置缓存数据"""
|
|
if not self.enabled:
|
|
return True
|
|
|
|
cache_key = self._get_cache_key(prefix, **kwargs)
|
|
cache_path = self._get_cache_path(cache_key)
|
|
|
|
try:
|
|
with open(cache_path, 'wb') as f:
|
|
pickle.dump(data, f)
|
|
return True
|
|
except (pickle.PickleError, IOError):
|
|
return False
|
|
|
|
def clear(self, prefix: Optional[str] = None) -> bool:
|
|
"""清除缓存"""
|
|
try:
|
|
if prefix:
|
|
# 清除特定前缀的缓存
|
|
for filename in os.listdir(self.cache_dir):
|
|
if filename.startswith(f"{prefix}_") and filename.endswith('.cache'):
|
|
os.remove(os.path.join(self.cache_dir, filename))
|
|
else:
|
|
# 清除所有缓存
|
|
for filename in os.listdir(self.cache_dir):
|
|
if filename.endswith('.cache'):
|
|
os.remove(os.path.join(self.cache_dir, filename))
|
|
return True
|
|
except OSError:
|
|
return False
|
|
|
|
def delete_pattern(self, pattern: str) -> bool:
|
|
"""删除匹配模式的缓存"""
|
|
try:
|
|
import glob
|
|
pattern_path = os.path.join(self.cache_dir, f"{pattern}_*.cache")
|
|
for cache_file in glob.glob(pattern_path):
|
|
os.remove(cache_file)
|
|
return True
|
|
except OSError:
|
|
return False
|
|
|
|
# 全局缓存实例
|
|
view_cache = ViewCache()
|
|
data_cache = ViewCache("data/cache/data", default_ttl=3600, enabled=True) # 数据缓存,默认1小时
|
|
|
|
def cache_view(prefix: str, ttl: Optional[int] = None, key_func=None):
|
|
"""
|
|
视图缓存装饰器
|
|
|
|
Args:
|
|
prefix: 缓存前缀
|
|
ttl: 缓存过期时间(秒),None表示使用默认值
|
|
key_func: 自定义缓存键生成函数,接收函数参数,返回字符串
|
|
"""
|
|
def decorator(func):
|
|
@wraps(func)
|
|
async def wrapper(*args, **kwargs):
|
|
# 如果禁用缓存,直接执行原函数
|
|
if not view_cache.enabled:
|
|
return await func(*args, **kwargs)
|
|
|
|
# 生成缓存键
|
|
if key_func:
|
|
cache_key_prefix = key_func(*args, **kwargs)
|
|
else:
|
|
cache_key_prefix = prefix
|
|
|
|
# 尝试从缓存获取
|
|
cached_result = view_cache.get(cache_key_prefix, ttl=ttl, **kwargs)
|
|
if cached_result is not None:
|
|
return cached_result
|
|
|
|
# 执行原函数
|
|
result = await func(*args, **kwargs)
|
|
|
|
# 缓存结果
|
|
view_cache.set(cache_key_prefix, result, **kwargs)
|
|
|
|
return result
|
|
return wrapper
|
|
return decorator
|
|
|
|
def clear_cache_pattern(pattern: str) -> bool:
|
|
"""清除匹配模式的缓存"""
|
|
return view_cache.delete_pattern(pattern)
|
|
|
|
def clear_all_cache() -> bool:
|
|
"""清除所有视图缓存"""
|
|
return view_cache.clear() |