diff --git a/src/main/java/com/alist/api/common/modules/file/FileController.java b/src/main/java/com/alist/api/common/modules/file/FileController.java index f050b75..8c9f3fa 100644 --- a/src/main/java/com/alist/api/common/modules/file/FileController.java +++ b/src/main/java/com/alist/api/common/modules/file/FileController.java @@ -102,21 +102,9 @@ public class FileController { @PostMapping("/tusHook") public ResponseEntity> tusHook(@RequestBody TusHookForm tusHookForm) { - // log.info("tusHookForm: {}", tusHookForm); - // fileService.insertFileAndSave(tusHookForm.tusHookDto()); - log.info("[tusHook] type={}", tusHookForm.getType()); - log.info("[tusHook] uploadId={}", tusHookForm.getTusHookEventForm().getTusHookUploadForm().getId()); - log.info("[tusHook] size={}", tusHookForm.getTusHookEventForm().getTusHookUploadForm().getSize()); - log.info("[tusHook] metaData={}", tusHookForm.getTusHookEventForm().getTusHookUploadForm().getMetaData()); - log.info("[tusHookDto] type={}", tusHookForm.tusHookDto().getType()); - log.info("[tusHookDto] uploadId={}", tusHookForm.tusHookDto().getUploadId()); - log.info("[tusHookDto] size={}", tusHookForm.tusHookDto().getSize()); - log.info("[tusHookDto] fileUuid={}", tusHookForm.tusHookDto().getFileUuid()); - log.info("[tusHookDto] filename={}", tusHookForm.tusHookDto().getFilename()); - log.info("[tusHookDto] filetype={}", tusHookForm.tusHookDto().getFiletype()); - - fileService.saveUploadStatusFromTusHook(tusHookForm.tusHookDto()); + fileService.updateFileUploadStatus(tusHookForm.tusHookDto()); + fileService.saveUploadStatusRedisTusHook(tusHookForm.tusHookDto()); return ApiResponse.entity("", ApiResponseCode.CODE_200); } diff --git a/src/main/java/com/alist/api/common/modules/file/dto/TusHookDto.java b/src/main/java/com/alist/api/common/modules/file/dto/TusHookDto.java index 65e9888..16a53fc 100644 --- a/src/main/java/com/alist/api/common/modules/file/dto/TusHookDto.java +++ b/src/main/java/com/alist/api/common/modules/file/dto/TusHookDto.java @@ -13,4 +13,6 @@ public class TusHookDto { private String fileUuid; private String filename; private String filetype; + private long uploadedBytes; + private int status; } diff --git a/src/main/java/com/alist/api/common/modules/file/dto/UploadStatusDto.java b/src/main/java/com/alist/api/common/modules/file/dto/UploadStatusDto.java index 6b7e95e..a30d34f 100644 --- a/src/main/java/com/alist/api/common/modules/file/dto/UploadStatusDto.java +++ b/src/main/java/com/alist/api/common/modules/file/dto/UploadStatusDto.java @@ -6,7 +6,7 @@ import lombok.Setter; @Getter @Setter public class UploadStatusDto { - private String fileMasterKey; + private String fileUuid; private String status; // PENDING, UPLOADING, DONE, FAILED private long uploadedBytes; private long totalBytes; diff --git a/src/main/java/com/alist/api/common/modules/file/form/UploadStatusForm.java b/src/main/java/com/alist/api/common/modules/file/form/UploadStatusForm.java index ed0fcef..8acfcf6 100644 --- a/src/main/java/com/alist/api/common/modules/file/form/UploadStatusForm.java +++ b/src/main/java/com/alist/api/common/modules/file/form/UploadStatusForm.java @@ -9,11 +9,11 @@ import lombok.Setter; @Setter public class UploadStatusForm { @NotBlank - private String fileMasterKey; + private String fileUuid; public UploadStatusDto uploadStatusDto() { UploadStatusDto uploadStatusDto = new UploadStatusDto(); - uploadStatusDto.setFileMasterKey(this.fileMasterKey == null ? null : this.fileMasterKey.trim()); + uploadStatusDto.setFileUuid(this.fileUuid == null ? null : this.fileUuid.trim()); return uploadStatusDto; } } diff --git a/src/main/java/com/alist/api/common/modules/file/mapper/FileMapper.java b/src/main/java/com/alist/api/common/modules/file/mapper/FileMapper.java index c0d7e8d..7ffffd1 100644 --- a/src/main/java/com/alist/api/common/modules/file/mapper/FileMapper.java +++ b/src/main/java/com/alist/api/common/modules/file/mapper/FileMapper.java @@ -1,9 +1,6 @@ package com.alist.api.common.modules.file.mapper; -import com.alist.api.common.modules.file.dto.FileUploadDto; -import com.alist.api.common.modules.file.dto.FileUploadItemDto; -import com.alist.api.common.modules.file.dto.UploadStartDto; -import com.alist.api.common.modules.file.dto.UploadTokenDto; +import com.alist.api.common.modules.file.dto.*; import org.apache.ibatis.annotations.Mapper; @Mapper @@ -17,4 +14,10 @@ public interface FileMapper { void insertFileDetailInit(FileUploadItemDto item); int selectFileDetailCountByFileUuidUserToKenIdx(UploadTokenDto uploadTokenDto); + + void insertFileUploadEventLog(TusHookDto tusHookDto); + + void updateFileDetailStatus(TusHookDto tusHookDto); + + void updateFileMasterAggregateByFileUuid(String fileUuid); } diff --git a/src/main/java/com/alist/api/common/modules/file/service/FileService.java b/src/main/java/com/alist/api/common/modules/file/service/FileService.java index 41a0bda..3b1b67e 100644 --- a/src/main/java/com/alist/api/common/modules/file/service/FileService.java +++ b/src/main/java/com/alist/api/common/modules/file/service/FileService.java @@ -119,40 +119,62 @@ public class FileService { return uploadTokenDto; } - public UploadStartDto insertFileMasterUpload(Integer userIdx, Integer userTokenIdx, UploadStartDto uploadStartDto) { - uploadStartDto.setFileMasterKey(UUID.randomUUID().toString()); - uploadStartDto.setUserIdx(userIdx); - uploadStartDto.setStatus(1); - uploadStartDto.setFolderPath(uploadStartDto.getFolderPath() == null ? "/" : uploadStartDto.getFolderPath()); - - fileMapper.insertFileMasterUpload(uploadStartDto); - - uploadStartDto.setUploadToken(jwtTokenProvider.createUploadToken(userTokenIdx)); - uploadStartDto.setTusEndpoint(tusEndpoint); - - return uploadStartDto; - } - public UploadStatusDto getUploadStatus(UploadStatusDto uploadStatusDto) { - String key = buildUploadStatusKey(uploadStatusDto.getFileMasterKey()); + String key = buildUploadStatusKey(uploadStatusDto.getFileUuid()); Map map = stringRedisTemplate.opsForHash().entries(key); if (map.isEmpty()) { return null; } - UploadStatusDto dto = new UploadStatusDto(); - dto.setFileMasterKey((String) map.getOrDefault("fileMasterKey", uploadStatusDto.getFileMasterKey())); - dto.setStatus((String) map.getOrDefault("status", "PENDING")); - dto.setUploadedBytes(parseLong(map.get("uploadedBytes"))); - dto.setTotalBytes(parseLong(map.get("totalBytes"))); - dto.setPercent((int) parseLong(map.get("percent"))); - dto.setUpdatedAt((String) map.getOrDefault("updatedAt", "")); + uploadStatusDto.setFileUuid((String) map.getOrDefault("fileUuid", uploadStatusDto.getFileUuid())); + uploadStatusDto.setStatus((String) map.getOrDefault("status", "PENDING")); + uploadStatusDto.setUploadedBytes(parseLong(map.get("uploadedBytes"))); + uploadStatusDto.setTotalBytes(parseLong(map.get("totalBytes"))); + uploadStatusDto.setPercent((int) parseLong(map.get("percent"))); + uploadStatusDto.setUpdatedAt((String) map.getOrDefault("updatedAt", "")); - return dto; + return uploadStatusDto; } - public void saveUploadStatusFromTusHook(TusHookDto tusHookDto) { + /*db에 상태값 저장*/ + public void updateFileUploadStatus(TusHookDto tusHookDto) { + if (tusHookDto == null || tusHookDto.getFileUuid() == null || tusHookDto.getFileUuid().isBlank()) { + return; + } + + String type = tusHookDto.getType() == null ? "" : tusHookDto.getType().trim().toLowerCase(); + long offset = tusHookDto.getOffset() == null ? 0L : tusHookDto.getOffset(); + long size = tusHookDto.getSize() == null ? 0L : tusHookDto.getSize(); + + fileMapper.insertFileUploadEventLog(tusHookDto); + + tusHookDto.setUploadedBytes(offset); + + switch (type) { + case "pre-create", "post-receive": + tusHookDto.setStatus(1); // UPLOADING + break; + case "post-finish": + tusHookDto.setStatus(3); // DONE + tusHookDto.setUploadedBytes(size); + break; + case "post-terminate": + tusHookDto.setStatus(5); // CANCELED (정책에 따라 FAILED=4) + break; + default: + return; + } + + fileMapper.updateFileDetailStatus(tusHookDto); + + if ("post-finish".equals(type) || "post-terminate".equals(type)) { + fileMapper.updateFileMasterAggregateByFileUuid(tusHookDto.getFileUuid()); + } + } + + /*레이디스에 상태값 저장*/ + public void saveUploadStatusRedisTusHook(TusHookDto tusHookDto) { if (tusHookDto == null || tusHookDto.getFileUuid() == null || tusHookDto.getFileUuid().isBlank()) { return; } @@ -186,10 +208,6 @@ public class FileService { stringRedisTemplate.expire(key, Duration.ofHours(24)); } - public void insertFileAndSave(TusHookDto tusHookDto) { - - } - private String buildUploadStatusKey(String fileUuid) { return "upload:alist:status:" + fileUuid; } @@ -217,7 +235,7 @@ public class FileService { } } - private void evictUploadAuthCacheByFileMasterKey(String fileUuid) { + private void evictUploadAuthCacheByFileUuid(String fileUuid) { try { String pattern = "upload:alist:auth:" + fileUuid + ":*"; var keys = stringRedisTemplate.keys(pattern); diff --git a/src/main/resources/mapper/common/file/FileMapper.xml b/src/main/resources/mapper/common/file/FileMapper.xml index ab25b1a..38001b1 100644 --- a/src/main/resources/mapper/common/file/FileMapper.xml +++ b/src/main/resources/mapper/common/file/FileMapper.xml @@ -24,12 +24,80 @@ /*FileMapper.insertFileMasterUpload*/ INSERT INTO ALISTLMS.FILE_MASTER2 ( - FILE_MASTER_KEY, USER_IDX, FILE_CATEGORY, FOLDER_PATH, STATUS, CREATE_MEMBER, UPDATE_MEMBER + FILE_MASTER_KEY, USER_IDX, FILE_CATEGORY, FOLDER_PATH, STATUS, CREATE_MEMBER, UPDATE_MEMBER ) values ( - #{fileMasterKey}, #{userIdx}, #{fileCategory}, #{folderPath}, #{status}, #{userIdx}, #{userIdx} + #{fileMasterKey}, #{userIdx}, #{fileCategory}, #{folderPath}, #{status}, #{userIdx}, #{userIdx} ) + + /*FileMapper.insertFileUploadEventLog*/ + INSERT INTO ALISTLMS.FILE_UPLOAD_EVENT_LOG ( + FILE_DETAIL_IDX, EVENT_TYPE, OFFSET_BYTES, BYTES_WRITTEN, HTTP_STATUS, MESSAGE, RAW_JSON + ) + SELECT + LFD.FILE_DETAIL_IDX + , #{type} + , #{offset} + , NULL + , NULL + , NULL + , NULL + FROM ALISTLMS.FILE_DETAIL LFD + WHERE LFD.FILE_UUID = #{fileUuid} + LIMIT 1 + + + + /*FileMapper.updateFileDetailStatus*/ + UPDATE ALISTLMS.FILE_DETAIL + + + TUS_UPLOAD_ID = #{uploadId}, + + + UPLOADED_BYTES = #{uploadedBytes}, + + + STATUS = #{status}, + + UPDATE_DATE = NOW() + + WHERE FILE_UUID = #{fileUuid} + AND DEL_YN = 'N' + + + + /*FileMapper.updateFileMasterAggregateByFileUuid*/ + UPDATE ALISTLMS.FILE_MASTER LFM + JOIN ( + SELECT + LLFD.FILE_MASTER_IDX, + COUNT(*) AS total_count, + SUM(CASE WHEN LLFD.STATUS = 3 THEN 1 ELSE 0 END) AS done_count, + SUM(CASE WHEN LLFD.STATUS IN (4,5) THEN 1 ELSE 0 END) AS fail_count + FROM ALISTLMS.FILE_DETAIL LLFD + WHERE LLFD.FILE_MASTER_IDX = ( + SELECT FILE_MASTER_IDX + FROM ALISTLMS.FILE_DETAIL + WHERE FILE_UUID = #{fileUuid} + LIMIT 1 + ) + AND LLFD.DEL_YN = 'N' + ) A ON A.FILE_MASTER_IDX = LFM.FILE_MASTER_IDX + SET LFM.TOTAL_COUNT = A.total_count, + LFM.DONE_COUNT = A.done_count, + LFM.FAIL_COUNT = A.fail_count, + LFM.STATUS = CASE + WHEN A.done_count = A.total_count THEN 3 + WHEN A.done_count = 0 AND A.fail_count = A.total_count THEN 4 + WHEN A.done_count > 0 AND A.fail_count > 0 THEN 5 + ELSE 1 + END, + LFM.UPDATE_DATE = NOW() + + +