diff --git a/app/src/main/kotlin/com/akagiyui/drive/controller/FileController.kt b/app/src/main/kotlin/com/akagiyui/drive/controller/FileController.kt index ff824e1..1c25a63 100644 --- a/app/src/main/kotlin/com/akagiyui/drive/controller/FileController.kt +++ b/app/src/main/kotlin/com/akagiyui/drive/controller/FileController.kt @@ -12,6 +12,7 @@ import com.akagiyui.drive.model.request.CreateUploadTaskRequest import com.akagiyui.drive.model.request.MirrorFileRequest import com.akagiyui.drive.model.response.FolderContentResponse import com.akagiyui.drive.model.response.FolderResponse +import com.akagiyui.drive.model.response.UploadTaskResponse import com.akagiyui.drive.model.response.UserFileResponse import com.akagiyui.drive.service.* import jakarta.servlet.http.HttpServletResponse @@ -120,6 +121,7 @@ class FileController( * @param chunk 分片文件 * @param chunkHash 分片哈希 * @param chunkIndex 分片索引 + * @return 是否已收到该任务的所有分片 */ @PostMapping("/task/{id}/chunk") @RequirePermission(Permission.PERSONAL_UPLOAD) @@ -129,8 +131,20 @@ class FileController( @RequestParam("hash") @Validated @Size(min = 64, max = 64) chunkHash: String, @RequestParam("index") @Validated @Min(0) chunkIndex: Int, @CurrentUser user: User, - ) { - uploadService.uploadChunk(user, taskId, chunk, chunkHash, chunkIndex) + ): Boolean { + return uploadService.uploadChunk(user, taskId, chunk, chunkHash, chunkIndex) + } + + /** + * 获取上传任务信息 + * + * @param taskId 任务ID + * @return 任务信息 + */ + @GetMapping("/task/{id}") + @RequirePermission(Permission.PERSONAL_UPLOAD) + fun getUploadTaskInfo(@PathVariable("id") taskId: String): UploadTaskResponse { + return UploadTaskResponse(uploadService.getUploadTask(taskId)) } /** diff --git a/app/src/main/kotlin/com/akagiyui/drive/entity/cache/UploadTask.kt b/app/src/main/kotlin/com/akagiyui/drive/entity/cache/UploadTask.kt index ca910e5..60789f4 100644 --- a/app/src/main/kotlin/com/akagiyui/drive/entity/cache/UploadTask.kt +++ b/app/src/main/kotlin/com/akagiyui/drive/entity/cache/UploadTask.kt @@ -65,4 +65,8 @@ class UploadTask { */ var allowUpload: Boolean = true + /** + * 合并完成 + */ + var merged: Boolean = false } diff --git a/app/src/main/kotlin/com/akagiyui/drive/model/response/UploadTaskResponse.kt b/app/src/main/kotlin/com/akagiyui/drive/model/response/UploadTaskResponse.kt new file mode 100644 index 0000000..df4a7f8 --- /dev/null +++ b/app/src/main/kotlin/com/akagiyui/drive/model/response/UploadTaskResponse.kt @@ -0,0 +1,13 @@ +package com.akagiyui.drive.model.response + +import com.akagiyui.drive.entity.cache.UploadTask + +/** + * 上传任务信息响应 + * @author AkagiYui + */ + +class UploadTaskResponse(task: UploadTask) { + val id = task.id + val merged = task.merged +} diff --git a/app/src/main/kotlin/com/akagiyui/drive/service/UploadService.kt b/app/src/main/kotlin/com/akagiyui/drive/service/UploadService.kt index b2c6293..54711ee 100644 --- a/app/src/main/kotlin/com/akagiyui/drive/service/UploadService.kt +++ b/app/src/main/kotlin/com/akagiyui/drive/service/UploadService.kt @@ -20,10 +20,15 @@ interface UploadService { /** * 上传分片 */ - fun uploadChunk(user: User, taskId: String, chunk: MultipartFile, chunkHash: String, chunkIndex: Int) + fun uploadChunk(user: User, taskId: String, chunk: MultipartFile, chunkHash: String, chunkIndex: Int): Boolean /** * 接收文件 */ fun receiveMultipartFiles(user: User, files: List, folder: String?): List + + /** + * 获取上传任务 + */ + fun getUploadTask(taskId: String): UploadTask } diff --git a/app/src/main/kotlin/com/akagiyui/drive/service/impl/UploadServiceImpl.kt b/app/src/main/kotlin/com/akagiyui/drive/service/impl/UploadServiceImpl.kt index 6876517..90d4c44 100644 --- a/app/src/main/kotlin/com/akagiyui/drive/service/impl/UploadServiceImpl.kt +++ b/app/src/main/kotlin/com/akagiyui/drive/service/impl/UploadServiceImpl.kt @@ -69,7 +69,13 @@ class UploadServiceImpl( } @Transactional - override fun uploadChunk(user: User, taskId: String, chunk: MultipartFile, chunkHash: String, chunkIndex: Int) { + override fun uploadChunk( + user: User, + taskId: String, + chunk: MultipartFile, + chunkHash: String, + chunkIndex: Int, + ): Boolean { val task = uploadTaskRepository.findById(taskId).orElseThrow { CustomException(ResponseEnum.TASK_NOT_FOUND) } @@ -115,19 +121,21 @@ class UploadServiceImpl( log.debug("task: $taskId, chunk: $chunkIndex, hash not match") throw CustomException(ResponseEnum.GENERAL_ERROR) } + log.debug("task: $taskId, chunk: $chunkIndex, upload success") // 标记已上传 redisCache.set("chunk_uploaded:$taskId", chunkIndex, true) val chunkMap = redisCache.getMap("chunk_uploaded:$taskId") - if (chunkMap.values.all { it }) { + return if (chunkMap.values.all { it }) { task.allowUpload = false uploadTaskRepository.save(task) taskExecutor.execute { mergeChunks(user, task) } + true } else { uploadTaskRepository.save(task) + false } - log.debug("task: $taskId, chunk: $chunkIndex, upload success") } private fun mergeChunks(user: User, task: UploadTask) { @@ -185,6 +193,8 @@ class UploadServiceImpl( } fileInfoService.addFileInfo(fileInfo) userFileService.addAssociation(user, fileInfo.name, fileInfo, task.folder) + task.merged = true + uploadTaskRepository.save(task) storageService.store(storageKey, cacheFile, task.fileType) { taskCacheDirectory.deleteRecursively() fileInfo.locked = false @@ -192,6 +202,12 @@ class UploadServiceImpl( } } + override fun getUploadTask(taskId: String): UploadTask { + return uploadTaskRepository.findById(taskId).orElseThrow { + CustomException(ResponseEnum.TASK_NOT_FOUND) + } + } + @Value("\${application.storage.local.cacheRoot}") private var uploadCacheFolder: String = "./" get() {