(
upload_id: str,
data: CompleteUploadModel = Depends(parse_complete_upload),
ip: str = Depends(ip_limit["upload"]),
)
| 557 | "/upload/complete/{upload_id}", dependencies=[Depends(share_required_login)] |
| 558 | ) |
| 559 | async def complete_upload( |
| 560 | upload_id: str, |
| 561 | data: CompleteUploadModel = Depends(parse_complete_upload), |
| 562 | ip: str = Depends(ip_limit["upload"]), |
| 563 | ): |
| 564 | # 获取上传基本信息 |
| 565 | chunk_info = await UploadChunk.filter(upload_id=upload_id, chunk_index=-1).first() |
| 566 | if not chunk_info: |
| 567 | raise HTTPException(status.HTTP_404_NOT_FOUND, detail="上传会话不存在") |
| 568 | |
| 569 | storage = storages[settings.file_storage]() |
| 570 | # 验证所有分片 |
| 571 | completed_chunks_list = await UploadChunk.filter( |
| 572 | upload_id=upload_id, completed=True |
| 573 | ).all() |
| 574 | if len(completed_chunks_list) != chunk_info.total_chunks: |
| 575 | raise HTTPException(status.HTTP_400_BAD_REQUEST, detail="分片不完整") |
| 576 | |
| 577 | # 用分片数 * chunk_size 校验最大可能大小 |
| 578 | max_total_size = len(completed_chunks_list) * chunk_info.chunk_size |
| 579 | if max_total_size > settings.uploadSize: |
| 580 | save_path = chunk_info.save_path |
| 581 | if save_path: |
| 582 | try: |
| 583 | await storage.clean_chunks(upload_id, save_path) |
| 584 | except Exception: |
| 585 | pass |
| 586 | await UploadChunk.filter(upload_id=upload_id).delete() |
| 587 | max_size_mb = settings.uploadSize / (1024 * 1024) |
| 588 | raise HTTPException( |
| 589 | status_code=403, detail=f"实际上传大小超过限制,最大为 {max_size_mb:.2f} MB" |
| 590 | ) |
| 591 | |
| 592 | save_path = chunk_info.save_path |
| 593 | path = os.path.dirname(save_path) if save_path else "" |
| 594 | prefix, suffix = os.path.splitext(chunk_info.file_name) |
| 595 | |
| 596 | try: |
| 597 | # 合并文件并计算哈希 |
| 598 | _, file_hash = await storage.merge_chunks(upload_id, chunk_info, save_path) |
| 599 | # 创建文件记录 |
| 600 | expired_at, expired_count, used_count, code = await get_expire_info( |
| 601 | data.expire_value, data.expire_style |
| 602 | ) |
| 603 | await FileCodes.create( |
| 604 | code=code, |
| 605 | file_hash=file_hash, # 使用合并后计算的哈希 |
| 606 | is_chunked=True, |
| 607 | upload_id=upload_id, |
| 608 | size=chunk_info.file_size, |
| 609 | expired_at=expired_at, |
| 610 | expired_count=expired_count, |
| 611 | used_count=used_count, |
| 612 | file_path=path, |
| 613 | uuid_file_name=f"{prefix}{suffix}", |
| 614 | prefix=prefix, |
| 615 | suffix=suffix, |
| 616 | ) |
nothing calls this directly
no test coverage detected