File size: 6,156 Bytes
b6db694 27beae4 b6db694 454f1d5 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 cc826a1 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 cc826a1 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 27beae4 b6db694 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | import os
import asyncio
import logging
import time
import aiofiles
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional
logger = logging.getLogger(__name__)
class FileCachePlugin:
"""文件缓存插件"""
def __init__(self):
self.name = "cache"
self.enabled = False
self.cache_dir = None
self.temp_dir = None
self.permanent_dir = None
self.file_metadata = {} # 存储文件元数据:{file_id: {"name": str, "type": str, "created": timestamp, "is_temp": bool}}
def on_enable(self):
"""插件启用时调用"""
self.enabled = True
self._init_directories()
self._load_metadata()
logger.info(f"{self.name} 已启用")
def on_disable(self):
"""插件禁用时调用"""
self.enabled = False
try:
from . import api
api.stop_cleanup_task()
except Exception as e:
logger.error(f"停止清理任务失败: {e}")
logger.info(f"{self.name} 已禁用")
def _init_directories(self):
"""初始化缓存目录"""
plugin_dir = Path(__file__).parent / "cache"
plugin_dir.mkdir(exist_ok=True)
self.cache_dir = plugin_dir
self.temp_dir = plugin_dir / "temp"
self.permanent_dir = plugin_dir / "permanent"
self.temp_dir.mkdir(exist_ok=True)
self.permanent_dir.mkdir(exist_ok=True)
def _load_metadata(self):
"""从缓存目录加载文件元数据"""
self.file_metadata = {}
# 加载临时文件
if self.temp_dir.exists():
for file_path in self.temp_dir.iterdir():
if file_path.is_file():
file_id = file_path.stem
stat = file_path.stat()
self.file_metadata[file_id] = {
"name": file_path.name,
"type": "temp",
"created": stat.st_mtime,
"path": str(file_path),
}
# 加载永久文件
if self.permanent_dir.exists():
for file_path in self.permanent_dir.iterdir():
if file_path.is_file():
file_id = file_path.stem
stat = file_path.stat()
self.file_metadata[file_id] = {
"name": file_path.name,
"type": "permanent",
"created": stat.st_mtime,
"path": str(file_path),
}
async def cleanup_expired_files(self):
"""清理超过8小时的临时文件"""
current_time = time.time()
expired_files = []
for file_id, metadata in list(self.file_metadata.items()):
if metadata["type"] == "temp":
file_age = current_time - metadata["created"]
# 8小时 = 28800秒
if file_age > 28800:
expired_files.append(file_id)
for file_id in expired_files:
await self.delete_file(file_id)
async def save_file(
self,
file_id: str,
file_content: bytes,
original_filename: str,
is_temp: bool = True,
) -> bool:
"""保存文件到缓存目录"""
try:
target_dir = self.temp_dir if is_temp else self.permanent_dir
file_path = target_dir / original_filename
# 如果文件已存在,添加时间戳以避免重名
if file_path.exists():
name, suffix = (
original_filename.rsplit(".", 1)
if "." in original_filename
else (original_filename, "")
)
timestamp = int(time.time() * 1000)
original_filename = (
f"{name}_{timestamp}.{suffix}" if suffix else f"{name}_{timestamp}"
)
file_path = target_dir / original_filename
# 保存文件
async with aiofiles.open(file_path, "wb") as f:
await f.write(file_content)
# 记录元数据
self.file_metadata[file_id] = {
"name": original_filename,
"type": "temp" if is_temp else "permanent",
"created": time.time(),
"path": str(file_path),
}
return True
except Exception as e:
logger.error(f"保存文件失败: {e}")
return False
async def delete_file(self, file_id: str) -> bool:
"""删除文件"""
try:
if file_id not in self.file_metadata:
return False
file_path = Path(self.file_metadata[file_id]["path"])
if file_path.exists():
file_path.unlink()
del self.file_metadata[file_id]
return True
except Exception as e:
logger.error(f"删除文件失败: {e}")
return False
def get_file_list(self) -> List[Dict]:
"""获取文件列表"""
file_list = []
for file_id, metadata in self.file_metadata.items():
file_list.append(
{
"file_id": file_id,
"name": metadata["name"],
"type": metadata["type"],
"created": datetime.fromtimestamp(metadata["created"]).isoformat(),
"url": f"/plugins/cache/api/file/{file_id}",
}
)
return file_list
def get_file_path(self, file_id: str) -> Optional[str]:
"""获取文件路径"""
if file_id in self.file_metadata:
return self.file_metadata[file_id]["path"]
return None
def get_status(self) -> Dict:
"""获取插件状态"""
return {
"name": self.name,
"enabled": self.enabled,
"file_count": len(self.file_metadata),
"cache_dir": str(self.cache_dir),
}
# 创建全局实例
plugin = FileCachePlugin()
|