Initial commit

This commit is contained in:
fawney19
2025-12-10 20:52:44 +08:00
commit f784106826
485 changed files with 110993 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
"""缓存插件包"""
from .base import CachePlugin
__all__ = ["CachePlugin"]
+218
View File
@@ -0,0 +1,218 @@
"""
缓存插件基类
定义缓存插件的接口
"""
import hashlib
import json
from abc import ABC, abstractmethod
from datetime import timedelta
from typing import Any, Dict, List, Optional
from ..common import BasePlugin, HealthStatus, PluginMetadata
class CachePlugin(BasePlugin):
"""
缓存插件基类
所有缓存插件必须继承此类并实现相关方法
"""
def __init__(
self,
name: str,
priority: int = 0,
version: str = "1.0.0",
author: str = "Unknown",
description: str = "",
api_version: str = "1.0",
dependencies: List[str] = None,
provides: List[str] = None,
config: Dict[str, Any] = None,
):
"""
初始化缓存插件
Args:
name: 插件名称
priority: 优先级
version: 插件版本
author: 插件作者
description: 插件描述
api_version: API版本
dependencies: 依赖列表
provides: 提供服务列表
config: 配置字典
"""
super().__init__(
name=name,
priority=priority,
version=version,
author=author,
description=description,
api_version=api_version,
dependencies=dependencies,
provides=provides,
config=config,
)
self.default_ttl = self.config.get("default_ttl", 3600) # 默认1小时
self.max_size = self.config.get("max_size", 1000) # 最大缓存项数
@abstractmethod
async def get(self, key: str) -> Optional[Any]:
"""
获取缓存值
Args:
key: 缓存键
Returns:
缓存值,如果不存在返回None
"""
pass
@abstractmethod
async def set(self, key: str, value: Any, ttl: Optional[int] = None) -> bool:
"""
设置缓存值
Args:
key: 缓存键
value: 缓存值
ttl: 过期时间(秒),None使用默认值
Returns:
是否成功设置
"""
pass
@abstractmethod
async def delete(self, key: str) -> bool:
"""
删除缓存项
Args:
key: 缓存键
Returns:
是否成功删除
"""
pass
@abstractmethod
async def exists(self, key: str) -> bool:
"""
检查缓存项是否存在
Args:
key: 缓存键
Returns:
是否存在
"""
pass
@abstractmethod
async def clear(self) -> bool:
"""
清空所有缓存
Returns:
是否成功清空
"""
pass
@abstractmethod
async def get_many(self, keys: List[str]) -> Dict[str, Any]:
"""
批量获取缓存值
Args:
keys: 缓存键列表
Returns:
键值对字典
"""
pass
@abstractmethod
async def set_many(self, items: Dict[str, Any], ttl: Optional[int] = None) -> bool:
"""
批量设置缓存值
Args:
items: 键值对字典
ttl: 过期时间(秒)
Returns:
是否成功设置
"""
pass
@abstractmethod
async def get_stats(self) -> Dict[str, Any]:
"""
获取缓存统计信息
Returns:
统计信息字典
"""
pass
def generate_key(self, *args, **kwargs) -> str:
"""
生成缓存键
Args:
*args: 位置参数
**kwargs: 关键字参数
Returns:
缓存键字符串
"""
# 创建一个稳定的键
key_parts = [str(arg) for arg in args]
key_parts.extend([f"{k}:{v}" for k, v in sorted(kwargs.items())])
key_string = "|".join(key_parts)
# 如果键太长,使用哈希
if len(key_string) > 250:
hash_obj = hashlib.md5(key_string.encode())
return f"{self.name}:{hash_obj.hexdigest()}"
return f"{self.name}:{key_string}"
def serialize(self, value: Any) -> str:
"""
序列化值
Args:
value: 要序列化的值
Returns:
序列化后的字符串
"""
return json.dumps(value, default=str)
def deserialize(self, value: str) -> Any:
"""
反序列化值
Args:
value: 序列化的字符串
Returns:
反序列化后的值
"""
return json.loads(value)
def configure(self, config: Dict[str, Any]):
"""
配置插件
Args:
config: 配置字典
"""
super().configure(config)
self.default_ttl = config.get("default_ttl", self.default_ttl)
self.max_size = config.get("max_size", self.max_size)
+195
View File
@@ -0,0 +1,195 @@
"""
内存缓存插件
基于Python字典的简单内存缓存实现
"""
import asyncio
import threading
import time
from collections import OrderedDict
from typing import Any, Dict, List, Optional
from .base import CachePlugin
class MemoryCachePlugin(CachePlugin):
"""
内存缓存插件
使用OrderedDict实现LRU缓存
"""
def __init__(self, name: str = "memory", config: Dict[str, Any] = None):
super().__init__(name, config)
self._cache: OrderedDict = OrderedDict()
self._expiry: Dict[str, float] = {}
self._lock = threading.RLock()
self._hits = 0
self._misses = 0
self._evictions = 0
self._cleanup_task = None
self._cleanup_interval = 60 # 默认值
# 启动清理任务
if config is not None:
self._cleanup_interval = config.get("cleanup_interval", 60)
try:
self._start_cleanup_task()
except:
pass # 忽略事件循环错误
def _start_cleanup_task(self):
"""启动后台清理任务"""
async def cleanup_loop():
while self.enabled:
await asyncio.sleep(self._cleanup_interval)
await self._cleanup_expired()
loop = asyncio.get_event_loop()
self._cleanup_task = loop.create_task(cleanup_loop())
async def _cleanup_expired(self):
"""清理过期的缓存项"""
now = time.time()
expired_keys = []
with self._lock:
for key, expiry in self._expiry.items():
if expiry < now:
expired_keys.append(key)
for key in expired_keys:
self._cache.pop(key, None)
self._expiry.pop(key, None)
self._evictions += 1
def _check_size(self):
"""检查并维护缓存大小限制"""
if len(self._cache) >= self.max_size:
# 删除最老的项(LRU)
key = next(iter(self._cache))
self._cache.pop(key)
self._expiry.pop(key, None)
self._evictions += 1
async def get(self, key: str) -> Optional[Any]:
"""获取缓存值"""
with self._lock:
# 检查是否过期
if key in self._expiry:
if self._expiry[key] < time.time():
# 已过期,删除
self._cache.pop(key, None)
self._expiry.pop(key)
self._misses += 1
return None
# 获取值并更新访问顺序(LRU)
if key in self._cache:
value = self._cache.pop(key)
self._cache[key] = value # 移到末尾
self._hits += 1
return self.deserialize(value) if isinstance(value, str) else value
else:
self._misses += 1
return None
async def set(self, key: str, value: Any, ttl: Optional[int] = None) -> bool:
"""设置缓存值"""
with self._lock:
# 检查大小限制
if key not in self._cache:
self._check_size()
# 序列化值
if not isinstance(value, str):
value = self.serialize(value)
# 设置值
self._cache[key] = value
self._cache.move_to_end(key) # 移到末尾(最新)
# 设置过期时间
if ttl is None:
ttl = self.default_ttl
if ttl > 0:
self._expiry[key] = time.time() + ttl
return True
async def delete(self, key: str) -> bool:
"""删除缓存项"""
with self._lock:
if key in self._cache:
self._cache.pop(key)
self._expiry.pop(key, None)
return True
return False
async def exists(self, key: str) -> bool:
"""检查缓存项是否存在"""
with self._lock:
# 检查是否过期
if key in self._expiry:
if self._expiry[key] < time.time():
# 已过期,删除
self._cache.pop(key, None)
self._expiry.pop(key)
return False
return key in self._cache
async def clear(self) -> bool:
"""清空所有缓存"""
with self._lock:
self._cache.clear()
self._expiry.clear()
return True
async def get_many(self, keys: List[str]) -> Dict[str, Any]:
"""批量获取缓存值"""
result = {}
for key in keys:
value = await self.get(key)
if value is not None:
result[key] = value
return result
async def set_many(self, items: Dict[str, Any], ttl: Optional[int] = None) -> bool:
"""批量设置缓存值"""
success = True
for key, value in items.items():
if not await self.set(key, value, ttl):
success = False
return success
async def get_stats(self) -> Dict[str, Any]:
"""获取缓存统计信息"""
total_requests = self._hits + self._misses
hit_rate = self._hits / total_requests if total_requests > 0 else 0
return {
"type": "memory",
"size": len(self._cache),
"max_size": self.max_size,
"hits": self._hits,
"misses": self._misses,
"hit_rate": hit_rate,
"evictions": self._evictions,
"cleanup_interval": self._cleanup_interval,
}
async def _do_shutdown(self):
"""清理资源"""
# 取消清理任务
if self._cleanup_task:
self._cleanup_task.cancel()
try:
await self._cleanup_task
except asyncio.CancelledError:
pass
def __del__(self):
"""清理资源"""
if hasattr(self, "_cleanup_task") and self._cleanup_task:
self._cleanup_task.cancel()