From b9c500dc8db165c01b3dcf0bafd09bca0eb205f5 Mon Sep 17 00:00:00 2001 From: guqing <38999863+guqing@users.noreply.github.com> Date: Mon, 1 Jul 2024 18:05:17 +0800 Subject: [PATCH] fix: handle plugin entry file loading when cache temp directory is cleared (#6238) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /kind bug /area plugin /milestone 2.17.x #### What this PR does / why we need it: 修复当插件入口文件的缓存目录被系统清理后会导致一直无法加载的问题 原问题复现步骤: 1. 登录后刷新页面,此时缓存目录被创建 2. 删除缓存目录后就会提示文件不存在然后导致插件入口文件一致无法加载直到重启 Halo #### Which issue(s) this PR fixes: Fixes #6226 #### Does this PR introduce a user-facing change? ```release-note 修复当插件入口文件的缓存目录被系统清理后会导致一直无法加载的问题 ``` --- .../service/impl/PluginServiceImpl.java | 25 ++++++++++++++++--- .../service/impl/PluginServiceImplTest.java | 19 ++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/run/halo/app/core/extension/service/impl/PluginServiceImpl.java b/application/src/main/java/run/halo/app/core/extension/service/impl/PluginServiceImpl.java index e891887f59..be5d5bd06e 100644 --- a/application/src/main/java/run/halo/app/core/extension/service/impl/PluginServiceImpl.java +++ b/application/src/main/java/run/halo/app/core/extension/service/impl/PluginServiceImpl.java @@ -549,15 +549,22 @@ Mono computeIfAbsent(String version, Publisher content) { // double check of the resource .filter(res -> isResourceMatch(res, newFilename)) .switchIfEmpty(Mono.using( - () -> tempDir.resolve(newFilename), + () -> { + if (!Files.exists(tempDir)) { + Files.createDirectories(tempDir); + } + return tempDir.resolve(newFilename); + }, path -> DataBufferUtils.write(content, path, CREATE, TRUNCATE_EXISTING) .then(Mono.fromSupplier( () -> new FileSystemResource(path) )), path -> { - // clean up old resource - cleanUp(this.resource); + if (shouldCleanUp(path)) { + // clean up old resource + cleanUp(this.resource); + } }) .subscribeOn(scheduler) .doOnNext(newResource -> this.resource = newResource) @@ -579,6 +586,18 @@ Mono computeIfAbsent(String version, Publisher content) { }); } + private boolean shouldCleanUp(Path newPath) { + if (this.resource == null || !this.resource.exists()) { + return false; + } + try { + var oldPath = this.resource.getFile().toPath(); + return !oldPath.equals(newPath); + } catch (IOException e) { + return false; + } + } + private static void cleanUp(Resource resource) { if (resource instanceof WritableResource wr && wr.isWritable() diff --git a/application/src/test/java/run/halo/app/core/extension/service/impl/PluginServiceImplTest.java b/application/src/test/java/run/halo/app/core/extension/service/impl/PluginServiceImplTest.java index 8d34e55d65..6918aba6e9 100644 --- a/application/src/test/java/run/halo/app/core/extension/service/impl/PluginServiceImplTest.java +++ b/application/src/test/java/run/halo/app/core/extension/service/impl/PluginServiceImplTest.java @@ -46,6 +46,7 @@ import org.pf4j.PluginDescriptor; import org.pf4j.PluginWrapper; import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.util.FileSystemUtils; import org.springframework.web.server.ServerWebInputException; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; @@ -391,6 +392,24 @@ void shouldComputeBundleFileIfAbsent() { } }) .verifyComplete(); + + try { + FileSystemUtils.deleteRecursively(tempDir); + } catch (IOException e) { + throw new RuntimeException(e); + } + cache.computeIfAbsent("fake-version", fakeContent) + .as(StepVerifier::create) + .assertNext(resource -> { + try { + assertThat(Files.exists(tempDir)).isTrue(); + assertEquals(tempDir.resolve("different-version.js"), + resource.getFile().toPath()); + } catch (IOException e) { + throw new RuntimeException(e); + } + }) + .verifyComplete(); } @Test