Skip to content

Commit

Permalink
refactor: add uniqueness check for local thumbnail original links and…
Browse files Browse the repository at this point in the history
… dimensions to avoid duplication (#7031)

#### What type of PR is this?
/kind improvement
/area core
/milestone 2.20.x

#### What this PR does / why we need it:
对本地缩略图的原图链接和尺寸增加唯一性检查避免重复

#### Does this PR introduce a user-facing change?

```release-note
对本地缩略图的原图链接和尺寸增加唯一性检查避免重复
```
  • Loading branch information
guqing authored Nov 24, 2024
1 parent 391aac6 commit 0b505a9
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
@GVK(group = "storage.halo.run", version = "v1alpha1", kind = "LocalThumbnail",
plural = "localthumbnails", singular = "localthumbnail")
public class LocalThumbnail extends AbstractExtension {
public static final String UNIQUE_IMAGE_AND_SIZE_INDEX = "uniqueImageAndSize";
public static final String REQUEST_TO_GENERATE_ANNO = "storage.halo.run/request-to-generate";

@Schema(requiredMode = REQUIRED)
Expand Down Expand Up @@ -80,4 +81,13 @@ public static class Status {
public enum Phase {
PENDING, SUCCEEDED, FAILED
}

public static String uniqueImageAndSize(LocalThumbnail localThumbnail) {
return uniqueImageAndSize(localThumbnail.getSpec().getImageSignature(),
localThumbnail.getSpec().getSize());
}

public static String uniqueImageAndSize(String imageSignature, ThumbnailSize size) {
return imageSignature + "-" + size.name();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ private static Path buildThumbnailStorePath(Path rootPath, String fileName, Stri
.resolve(fileName);
}

static String geImageFileName(URL imageUrl) {
var fileName = substringAfterLast(imageUrl.getPath(), "/");
static String geImageFileName(URI imageUri) {
var fileName = substringAfterLast(imageUri.getPath(), "/");
fileName = defaultIfBlank(fileName, randomAlphanumeric(10));
return ThumbnailGenerator.sanitizeFileName(fileName);
}
Expand Down Expand Up @@ -113,11 +113,12 @@ private Mono<LocalThumbnail> fetchThumbnail(URI thumbnailUri) {

private Mono<LocalThumbnail> fetchByImageHashAndSize(String imageSignature,
ThumbnailSize size) {
var indexValue = LocalThumbnail.uniqueImageAndSize(imageSignature, size);
return client.listBy(LocalThumbnail.class, ListOptions.builder()
.fieldQuery(equal("spec.imageSignature", imageSignature))
.build(), PageRequestImpl.ofSize(ThumbnailSize.values().length))
.fieldQuery(equal(LocalThumbnail.UNIQUE_IMAGE_AND_SIZE_INDEX, indexValue))
.build(), PageRequestImpl.ofSize(ThumbnailSize.values().length)
)
.flatMapMany(result -> Flux.fromIterable(result.getItems()))
.filter(thumbnail -> thumbnail.getSpec().getSize().equals(size))
.next();
}

Expand Down Expand Up @@ -158,9 +159,15 @@ private Mono<Void> updateWithRetry(LocalThumbnail localThumbnail, Consumer<Local
public Mono<LocalThumbnail> create(URL imageUrl, ThumbnailSize size) {
Assert.notNull(imageUrl, "Image URL must not be null.");
Assert.notNull(size, "Thumbnail size must not be null.");
var year = getYear();
var originalFileName = geImageFileName(imageUrl);
var imageUri = URI.create(imageUrl.toString());
var imageHash = signatureForImageUri(imageUri);
return fetchByImageHashAndSize(imageHash, size)
.switchIfEmpty(Mono.defer(() -> doCreate(imageUri, size)));
}

private Mono<LocalThumbnail> doCreate(URI imageUri, ThumbnailSize size) {
var year = getYear();
var originalFileName = geImageFileName(imageUri);
return generateUniqueThumbFileName(originalFileName, year, size)
.flatMap(thumbFileName -> {
var filePath =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,14 @@ public void onApplicationEvent(@NonNull ApplicationContextInitializedEvent event
);
});
schemeManager.register(LocalThumbnail.class, indexSpec -> {
// make sure image and size are unique
indexSpec.add(new IndexSpec()
.setUnique(true)
.setName(LocalThumbnail.UNIQUE_IMAGE_AND_SIZE_INDEX)
.setIndexFunc(simpleAttribute(LocalThumbnail.class,
LocalThumbnail::uniqueImageAndSize)
)
);
indexSpec.add(new IndexSpec()
.setName("spec.imageSignature")
.setIndexFunc(simpleAttribute(LocalThumbnail.class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
Expand All @@ -20,6 +21,7 @@
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.web.util.UriUtils;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import run.halo.app.core.attachment.AttachmentRootGetter;
Expand Down Expand Up @@ -61,14 +63,14 @@ void endpointForTest() {
@Test
void geImageFileNameTest() throws MalformedURLException {
var fileName =
LocalThumbnailServiceImpl.geImageFileName(new URL("https://halo.run/example.jpg"));
LocalThumbnailServiceImpl.geImageFileName(URI.create("https://halo.run/example.jpg"));
assertThat(fileName).isEqualTo("example.jpg");

fileName = LocalThumbnailServiceImpl.geImageFileName(new URL("https://halo.run/"));
fileName = LocalThumbnailServiceImpl.geImageFileName(URI.create("https://halo.run/"));
assertThat(fileName).isNotBlank();

fileName = LocalThumbnailServiceImpl.geImageFileName(
new URL("https://halo.run/.1fasfg(*&^%$.jpg"));
var encoded = UriUtils.encode("https://halo.run/.1fasfg(*&^%$.jpg", StandardCharsets.UTF_8);
fileName = LocalThumbnailServiceImpl.geImageFileName(URI.create(encoded));
assertThat(fileName).isNotBlank();
}

Expand Down

0 comments on commit 0b505a9

Please sign in to comment.