mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-10 19:29:50 +08:00
Initial commit
This commit is contained in:
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
"""缓存插件包"""
|
||||
|
||||
from .base import CachePlugin
|
||||
|
||||
__all__ = ["CachePlugin"]
|
||||
Vendored
+218
@@ -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)
|
||||
Vendored
+195
@@ -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()
|
||||
Reference in New Issue
Block a user