From f65c5ad860335e89f6d4788473ce6d538873e23e Mon Sep 17 00:00:00 2001 From: root Date: Tue, 8 Sep 2026 09:19:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=88=E4=BF=9D=E5=AD=98=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=86=8D=E4=B8=8B=E5=8F=91=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E4=BB=A5=E4=BF=9D=E7=95=99=E5=8D=B3=E6=97=B6=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dao/normal/CustomConfigurationMapper.java | 3 + .../Service/GalleryManageService.java | 24 +++----- .../Service/GallerySubmissionTest.java | 57 +++++++++++++++++++ 3 files changed, 69 insertions(+), 15 deletions(-) create mode 100644 src/test/java/com/lion/lionwebsite/Service/GallerySubmissionTest.java diff --git a/src/main/java/com/lion/lionwebsite/Dao/normal/CustomConfigurationMapper.java b/src/main/java/com/lion/lionwebsite/Dao/normal/CustomConfigurationMapper.java index 380e0a7..361875e 100644 --- a/src/main/java/com/lion/lionwebsite/Dao/normal/CustomConfigurationMapper.java +++ b/src/main/java/com/lion/lionwebsite/Dao/normal/CustomConfigurationMapper.java @@ -16,6 +16,9 @@ public interface CustomConfigurationMapper { // @Delete("delete from customConfiguration where parameter=#{parameter}") // void deleteConfiguration(CustomConfiguration configuration); + @Update("update customConfiguration set value=cast(value as integer)+#{amount} where parameter=#{parameter}") + void incrementConfiguration(@Param("parameter") String parameter, @Param("amount") long amount); + @Select("select * from customConfiguration where parameter=#{parameter}") CustomConfiguration selectConfiguration(String parameter); } diff --git a/src/main/java/com/lion/lionwebsite/Service/GalleryManageService.java b/src/main/java/com/lion/lionwebsite/Service/GalleryManageService.java index 49a60d6..06e39f0 100644 --- a/src/main/java/com/lion/lionwebsite/Service/GalleryManageService.java +++ b/src/main/java/com/lion/lionwebsite/Service/GalleryManageService.java @@ -93,9 +93,14 @@ public class GalleryManageService { } else { taskName = gallery.getName(); log.info("创建任务: {} 目标分辨率:{}", link, targetResolution); + // Persist before dispatch: the node sends its current status before its ACK. + gallery.setDownloader(user.getId()); + gallery.set_download(true); + galleryMapper.insertGallery(gallery); + configurationMapper.incrementConfiguration(CustomConfiguration.WEEK_USED_AMOUNT, gallery.getFileSize()); if (remoteService.addGalleryToQueue(gallery) != 0) { log.error("传送任务{}失败, 未知原因", gallery.getName()); - response.failure("任务传送失败,未知原因,尝试点击重连按钮看看"); + response.failure("任务已保存,但节点未确认接收;请刷新任务列表后重试"); pushService.taskCreateReport(user.getUsername(), taskName, response); return response.toJSONString(); } @@ -111,20 +116,9 @@ public class GalleryManageService { return response.toJSONString(); } - //处理下载结果,将任务插入数据库并且更新每周用量 - if (gallery.getStatus().equals("已提交")) { - response.success(gallery.toString()); - gallery.setDownloader(user.getId()); - gallery.set_download(true); - galleryMapper.insertGallery(gallery); - - long usedAmount = Long.parseLong(configurationMapper.selectConfiguration(CustomConfiguration.WEEK_USED_AMOUNT).getValue()); - usedAmount += gallery.getFileSize(); - configurationMapper.updateConfiguration(CustomConfiguration.WEEK_USED_AMOUNT, String.valueOf(usedAmount)); - } else { - response.failure("提交失败,未知原因"); - galleryMapper.deleteGalleryByGid(gallery.getGid()); - } + // Do not overwrite an immediate node status with the original submitted state. + Gallery current = galleryMapper.selectGalleryByGid(gallery.getGid()); + response.success((current == null ? gallery : current).toString()); pushService.taskCreateReport(user.getUsername(), taskName, response); return response.toJSONString(); diff --git a/src/test/java/com/lion/lionwebsite/Service/GallerySubmissionTest.java b/src/test/java/com/lion/lionwebsite/Service/GallerySubmissionTest.java new file mode 100644 index 0000000..0e5c49a --- /dev/null +++ b/src/test/java/com/lion/lionwebsite/Service/GallerySubmissionTest.java @@ -0,0 +1,57 @@ +package com.lion.lionwebsite.Service; + +import com.lion.lionwebsite.Dao.normal.*; +import com.lion.lionwebsite.Dao.cache.ImageCacheMapper; +import com.lion.lionwebsite.Domain.*; +import com.lion.lionwebsite.Util.GalleryUtil; +import org.junit.jupiter.api.Test; +import java.util.concurrent.atomic.AtomicReference; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class GallerySubmissionTest { + @Test + void immediateCompletionSeesPersistedTask() throws Exception { + checkSubmission((byte) 0); + } + + @Test + void timeoutRetainsTaskForRetry() throws Exception { + checkSubmission((byte) -1); + } + + private void checkSubmission(byte ack) throws Exception { + GalleryMapper galleries = mock(GalleryMapper.class); + UserMapper users = mock(UserMapper.class); + RemoteService remote = mock(RemoteService.class); + CustomConfigurationMapper configuration = mock(CustomConfigurationMapper.class); + GalleryManageService service = new GalleryManageService(galleries, mock(CollectMapper.class), configuration, + users, mock(ShareFileMapper.class), mock(ImageCacheMapper.class), remote, mock(PushService.class)); + User user = new User(); + user.setId(7); + user.setUsername("test"); + when(users.selectUserByAuthCode("test")).thenReturn(user); + AtomicReference saved = new AtomicReference<>(); + when(galleries.selectGalleryByGid(123)).thenAnswer(call -> saved.get()); + doAnswer(call -> { saved.set(call.getArgument(0)); return null; }).when(galleries).insertGallery(any()); + Gallery gallery = new Gallery(); + gallery.setGid(123); + gallery.setName("sample [123]"); + gallery.setStatus("已提交"); + when(remote.addGalleryToQueue(any())).thenAnswer(call -> { + assertNotNull(saved.get(), "node status must find a persisted record"); + assertEquals(7, saved.get().getDownloader()); + if (ack == 0) saved.get().setStatus("下载完成"); + return ack; + }); + try (var parser = mockStatic(GalleryUtil.class)) { + parser.when(() -> GalleryUtil.parse("https://example.org/g/123/key/", true, "original")).thenReturn(gallery); + String response = service.createTask("https://example.org/g/123/key/", "original", "test"); + assertNotNull(saved.get()); + assertTrue(response.contains(ack == 0 ? "success" : "任务已保存")); + assertEquals(ack == 0 ? "下载完成" : "已提交", saved.get().getStatus()); + verify(galleries, never()).deleteGalleryByGid(any()); + verify(galleries, times(1)).insertGallery(gallery); + } + } +}