(
upload_id: str,
chunk_index: int,
chunk: UploadFile = File(...),
)
| 426 | dependencies=[Depends(share_required_login)], |
| 427 | ) |
| 428 | async def upload_chunk( |
| 429 | upload_id: str, |
| 430 | chunk_index: int, |
| 431 | chunk: UploadFile = File(...), |
| 432 | ): |
| 433 | # 获取上传会话信息 |
| 434 | chunk_info = await UploadChunk.filter(upload_id=upload_id, chunk_index=-1).first() |
| 435 | if not chunk_info: |
| 436 | raise HTTPException(status.HTTP_404_NOT_FOUND, detail="上传会话不存在") |
| 437 | |
| 438 | # 检查分片索引有效性 |
| 439 | if chunk_index < 0 or chunk_index >= chunk_info.total_chunks: |
| 440 | raise HTTPException(status.HTTP_400_BAD_REQUEST, detail="无效的分片索引") |
| 441 | |
| 442 | # 检查是否已上传(支持断点续传) |
| 443 | existing_chunk = await UploadChunk.filter( |
| 444 | upload_id=upload_id, chunk_index=chunk_index, completed=True |
| 445 | ).first() |
| 446 | if existing_chunk: |
| 447 | return APIResponse( |
| 448 | detail={"chunk_hash": existing_chunk.chunk_hash, "skipped": True} |
| 449 | ) |
| 450 | |
| 451 | # 读取分片数据并计算哈希 |
| 452 | chunk_data = await chunk.read() |
| 453 | chunk_size = len(chunk_data) |
| 454 | |
| 455 | # 校验分片大小不超过声明的 chunk_size |
| 456 | if chunk_size > chunk_info.chunk_size: |
| 457 | raise HTTPException( |
| 458 | status.HTTP_400_BAD_REQUEST, |
| 459 | detail=f"分片大小超过声明值: 最大 {chunk_info.chunk_size}, 实际 {chunk_size}", |
| 460 | ) |
| 461 | |
| 462 | # 计算已上传分片数,校验累计大小不超限(用分片数 * chunk_size 估算) |
| 463 | uploaded_count = await UploadChunk.filter( |
| 464 | upload_id=upload_id, completed=True |
| 465 | ).count() |
| 466 | # 已上传分片的最大可能大小 + 当前分片 |
| 467 | max_uploaded_size = uploaded_count * chunk_info.chunk_size + chunk_size |
| 468 | if max_uploaded_size > settings.uploadSize: |
| 469 | max_size_mb = settings.uploadSize / (1024 * 1024) |
| 470 | raise HTTPException( |
| 471 | status_code=403, detail=f"累计上传大小超过限制,最大为 {max_size_mb:.2f} MB" |
| 472 | ) |
| 473 | |
| 474 | chunk_hash = hashlib.sha256(chunk_data).hexdigest() |
| 475 | |
| 476 | save_path = chunk_info.save_path |
| 477 | |
| 478 | # 保存分片到存储 |
| 479 | storage = storages[settings.file_storage]() |
| 480 | try: |
| 481 | await storage.save_chunk( |
| 482 | upload_id, chunk_index, chunk_data, chunk_hash, save_path |
| 483 | ) |
| 484 | except Exception as e: |
| 485 | raise HTTPException( |
nothing calls this directly
no test coverage detected