From 4f10c0800bf8025b78236841d8cd8dc56ab3a199 Mon Sep 17 00:00:00 2001 From: Lan Date: Mon, 1 Dec 2025 11:30:52 +0800 Subject: [PATCH] fix: some error --- .gitignore | 5 ++++- apps/admin/services.py | 12 ++++++++---- apps/base/utils.py | 4 ++-- apps/base/views.py | 16 ++++++++++++---- core/storage.py | 13 ++++--------- core/tasks.py | 10 ++++++++-- core/utils.py | 4 +--- 7 files changed, 39 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index db3620d..db9bc5c 100644 --- a/.gitignore +++ b/.gitignore @@ -156,4 +156,7 @@ data/.env /cloc-1.64.exe # Ignore node_modules -node_modules/ \ No newline at end of file +node_modules/ + + +AGENTS.md \ No newline at end of file diff --git a/apps/admin/services.py b/apps/admin/services.py index c012772..2c647e3 100644 --- a/apps/admin/services.py +++ b/apps/admin/services.py @@ -123,10 +123,14 @@ class LocalFileClass: def __init__(self, file): self.file = file self.path = data_root / "local" / file - self.ctime = time.strftime( - "%Y-%m-%d %H:%M:%S", time.localtime(os.path.getctime(self.path)) - ) - self.size = os.path.getsize(self.path) + if os.path.exists(self.path): + self.ctime = time.strftime( + "%Y-%m-%d %H:%M:%S", time.localtime(os.path.getctime(self.path)) + ) + self.size = os.path.getsize(self.path) + else: + self.ctime = None + self.size = None async def read(self): return open(self.path, "rb") diff --git a/apps/base/utils.py b/apps/base/utils.py index 3f9bdbe..1157353 100644 --- a/apps/base/utils.py +++ b/apps/base/utils.py @@ -109,6 +109,6 @@ async def calculate_file_hash(file: UploadFile, chunk_size=1024 * 1024) -> str: ip_limit = { - "error": IPRateLimit(count=settings.uploadCount, minutes=settings.errorMinute), - "upload": IPRateLimit(count=settings.errorCount, minutes=settings.errorMinute), + "error": IPRateLimit(count=settings.errorCount, minutes=settings.errorMinute), + "upload": IPRateLimit(count=settings.uploadCount, minutes=settings.uploadMinute), } diff --git a/apps/base/views.py b/apps/base/views.py index 6bdbd35..a0502c9 100644 --- a/apps/base/views.py +++ b/apps/base/views.py @@ -16,12 +16,19 @@ from core.utils import get_select_token share_api = APIRouter(prefix="/share", tags=["分享"]) -async def validate_file_size(file: UploadFile, max_size: int): - if file.size > max_size: +async def validate_file_size(file: UploadFile, max_size: int) -> int: + size = file.size + if size is None: + # 读取流计算大小,保持指针复位 + await file.seek(0, 2) + size = file.file.tell() + await file.seek(0) + if size > max_size: max_size_mb = max_size / (1024 * 1024) raise HTTPException( status_code=403, detail=f"大小超过限制,最大为{max_size_mb:.2f} MB" ) + return size async def create_file_code(code, **kwargs): @@ -63,7 +70,7 @@ async def share_file( file: UploadFile = File(...), ip: str = Depends(ip_limit["upload"]), ): - await validate_file_size(file, settings.uploadSize) + file_size = await validate_file_size(file, settings.uploadSize) if expire_style not in settings.expireStyle: raise HTTPException(status_code=400, detail="过期时间类型错误") expired_at, expired_count, used_count, code = await get_expire_info(expire_value, expire_style) @@ -76,7 +83,7 @@ async def share_file( suffix=suffix, uuid_file_name=uuid_file_name, file_path=path, - size=file.size, + size=file_size, expired_at=expired_at, expired_count=expired_count, used_count=used_count, @@ -141,6 +148,7 @@ async def download_file(key: str, code: str, ip: str = Depends(ip_limit["error"] file_storage: FileStorageInterface = storages[settings.file_storage]() if await get_select_token(code) != key: ip_limit["error"].add_ip(ip) + raise HTTPException(status_code=403, detail="下载鉴权失败") has, file_code = await get_code_file_by_code(code, False) if not has: return APIResponse(code=404, detail="文件不存在") diff --git a/core/storage.py b/core/storage.py index ea40bea..8af2bb3 100644 --- a/core/storage.py +++ b/core/storage.py @@ -27,14 +27,6 @@ from fastapi.responses import FileResponse class FileStorageInterface: - _instance: Optional["FileStorageInterface"] = None - - def __new__(cls, *args, **kwargs): - if cls._instance is None: - cls._instance = super(FileStorageInterface, cls).__new__( - cls, *args, **kwargs - ) - return cls._instance async def save_file(self, file: UploadFile, save_path: str): """ @@ -191,7 +183,10 @@ class SystemFileStorage(FileStorageInterface): """ chunk_dir = (self.root_path / save_path).parent / 'chunks' if chunk_dir.exists(): - shutil.rmtree(chunk_dir) + try: + shutil.rmtree(chunk_dir) + except Exception as e: + logger.info(f"清理本地分片目录失败: {e}") class S3FileStorage(FileStorageInterface): diff --git a/core/tasks.py b/core/tasks.py index f3da5a6..356ba1f 100644 --- a/core/tasks.py +++ b/core/tasks.py @@ -30,8 +30,14 @@ async def delete_expire_files(): Q(expired_at__lt=await get_now()) | Q(expired_count=0) ).all() for exp in expire_data: - await file_storage.delete_file(exp) - await exp.delete() + try: + await file_storage.delete_file(exp) + except Exception as e: + logging.error(f"删除过期文件失败 code={exp.code}: {e}") + try: + await exp.delete() + except Exception as e: + logging.error(f"删除记录失败 code={exp.code}: {e}") except Exception as e: logging.error(e) finally: diff --git a/core/utils.py b/core/utils.py index 85e95bf..e1dcf70 100644 --- a/core/utils.py +++ b/core/utils.py @@ -46,9 +46,7 @@ async def get_select_token(code: str): :return: """ token = settings.admin_token - return hashlib.sha256( - f"{code}{int(time.time() / 1000)}000{token}".encode() - ).hexdigest() + return hashlib.sha256(f"{code}{int(time.time() / 1000)}000{token}".encode()).hexdigest() async def get_file_url(code: str):