Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.itzg.helpers.files;
package me.itzg.helpers.cache;

import java.io.IOException;
import reactor.core.publisher.Mono;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package me.itzg.helpers.files;
package me.itzg.helpers.cache;

import java.io.IOException;
import reactor.core.publisher.Mono;

public class DisabledApiCaching implements ApiCaching {
public class ApiCachingDisabled implements ApiCaching {

@Override
public <R> Mono<R> cache(String operation, Class<R> returnType, Mono<R> resolver, Object... keys) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package me.itzg.helpers.files;
package me.itzg.helpers.cache;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.TemporalAmount;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
Expand All @@ -14,9 +15,10 @@
import java.util.stream.Stream;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import me.itzg.helpers.files.CacheIndex.CacheEntry;
import me.itzg.helpers.cache.CacheIndex.CacheEntry;
import me.itzg.helpers.json.ObjectMappers;
import org.jetbrains.annotations.Blocking;
import org.jetbrains.annotations.Nullable;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

Expand All @@ -30,10 +32,17 @@ public class ApiCachingImpl implements ApiCaching {
private final Path cacheNamespaceDir;

@Setter
private Duration cacheDuration = Duration.ofHours(24);
private Duration defaultCacheDuration = Duration.ofHours(48);

@Setter
private Map<String/*operation*/,Duration> cacheDurations = new HashMap<>();

@Blocking
public ApiCachingImpl(Path outputDirectory, String namespace) throws IOException {
public ApiCachingImpl(Path outputDirectory, String namespace, @Nullable CacheArgs cacheArgs) throws IOException {
if (cacheArgs != null) {
defaultCacheDuration = cacheArgs.getDefaultCacheDuration();
cacheDurations = cacheArgs.getCacheDurations();
}
objectMapper = ObjectMappers.defaultMapper();
cacheNamespaceDir = outputDirectory.resolve(CACHE_SUBIDR).resolve(namespace);
cacheIndex = loadCacheIndex();
Expand Down Expand Up @@ -110,7 +119,9 @@ private <R> Mono<R> saveToCache(String operation, String keys, R value) {
synchronized (cacheIndex) {
cacheIndex.getOperations().computeIfAbsent(operation, s -> new HashMap<>())
.put(keys, new CacheEntry()
.setExpiresAt(Instant.now().plus(cacheDuration))
.setExpiresAt(Instant.now().plus(
lookupCacheDuration(operation)
))
.setFilename(filename)
);
}
Expand All @@ -126,6 +137,12 @@ private <R> Mono<R> saveToCache(String operation, String keys, R value) {
.subscribeOn(Schedulers.boundedElastic());
}

private TemporalAmount lookupCacheDuration(String operation) {
return cacheDurations != null ?
cacheDurations.getOrDefault(operation, defaultCacheDuration)
: defaultCacheDuration;
}

private <R> Mono<R> loadFromCache(String operation, String keys, CacheEntry entry, Class<R> returnType) {

return Mono.fromCallable(() -> {
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/me/itzg/helpers/cache/CacheArgs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package me.itzg.helpers.cache;

import java.time.Duration;
import java.util.Map;
import lombok.Data;
import picocli.CommandLine.Option;

@Data
public class CacheArgs {
@Option(names = "--api-cache-ttl", paramLabel = "OPERATION=DURATION",
description = "Set individual operation TTLs"
)
Map<String, Duration> cacheDurations;

@Option(names = "--api-cache-default-ttl", defaultValue = "P2D", paramLabel = "DURATION",
description = "Set default/fallback TTL in ISO-8601 duration format.\nDefault: ${DEFAULT-VALUE}"
)
Duration defaultCacheDuration;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.itzg.helpers.files;
package me.itzg.helpers.cache;

import java.time.Instant;
import java.util.HashMap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import me.itzg.helpers.cache.ApiCaching;
import me.itzg.helpers.curseforge.model.Category;
import me.itzg.helpers.curseforge.model.CurseForgeFile;
import me.itzg.helpers.curseforge.model.CurseForgeMod;
Expand All @@ -21,7 +22,6 @@
import me.itzg.helpers.curseforge.model.ModsSearchResponse;
import me.itzg.helpers.errors.GenericException;
import me.itzg.helpers.errors.InvalidParameterException;
import me.itzg.helpers.files.ApiCaching;
import me.itzg.helpers.http.FailedRequestException;
import me.itzg.helpers.http.Fetch;
import me.itzg.helpers.http.FileDownloadStatusHandler;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import me.itzg.helpers.cache.ApiCaching;
import me.itzg.helpers.cache.ApiCachingDisabled;
import me.itzg.helpers.cache.ApiCachingImpl;
import me.itzg.helpers.cache.CacheArgs;
import me.itzg.helpers.curseforge.CurseForgeFilesManifest.FileEntry;
import me.itzg.helpers.curseforge.model.Category;
import me.itzg.helpers.curseforge.model.CurseForgeFile;
Expand All @@ -24,9 +28,6 @@
import me.itzg.helpers.curseforge.model.ModLoaderType;
import me.itzg.helpers.errors.GenericException;
import me.itzg.helpers.errors.InvalidParameterException;
import me.itzg.helpers.files.ApiCaching;
import me.itzg.helpers.files.ApiCachingImpl;
import me.itzg.helpers.files.DisabledApiCaching;
import me.itzg.helpers.files.Manifests;
import me.itzg.helpers.http.SharedFetchArgs;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -99,6 +100,9 @@ public void setSlugCategory(String defaultCategory) {
@Option(names = "--disable-api-caching", defaultValue = "${env:CF_DISABLE_API_CACHING:-false}")
boolean disableApiCaching;

@ArgGroup(exclusive = false)
CacheArgs cacheArgs;

@ArgGroup(exclusive = false)
SharedFetchArgs sharedFetchArgs = new SharedFetchArgs();

Expand All @@ -123,7 +127,8 @@ public Integer call() throws Exception {

if (modFileRefs != null && !modFileRefs.isEmpty()) {
try (
final ApiCaching apiCaching = disableApiCaching ? new DisabledApiCaching() : new ApiCachingImpl(outputDir, CACHING_NAMESPACE);
final ApiCaching apiCaching = disableApiCaching ? new ApiCachingDisabled()
: new ApiCachingImpl(outputDir, CACHING_NAMESPACE, cacheArgs);
final CurseForgeApiClient apiClient = new CurseForgeApiClient(
apiBaseUrl, apiKey, sharedFetchArgs.options(),
CurseForgeApiClient.MINECRAFT_GAME_ID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import me.itzg.helpers.cache.ApiCaching;
import me.itzg.helpers.cache.ApiCachingDisabled;
import me.itzg.helpers.cache.ApiCachingImpl;
import me.itzg.helpers.cache.CacheArgs;
import me.itzg.helpers.curseforge.ExcludeIncludesContent.ExcludeIncludes;
import me.itzg.helpers.curseforge.OverridesApplier.Result;
import me.itzg.helpers.curseforge.model.Category;
Expand All @@ -45,9 +49,6 @@
import me.itzg.helpers.errors.InvalidParameterException;
import me.itzg.helpers.errors.RateLimitException;
import me.itzg.helpers.fabric.FabricLauncherInstaller;
import me.itzg.helpers.files.ApiCaching;
import me.itzg.helpers.files.ApiCachingImpl;
import me.itzg.helpers.files.DisabledApiCaching;
import me.itzg.helpers.files.Manifests;
import me.itzg.helpers.files.ResultsFileWriter;
import me.itzg.helpers.forge.ForgeInstaller;
Expand Down Expand Up @@ -134,6 +135,9 @@ public class CurseForgeInstaller {
@Getter @Setter
private boolean disableApiCaching;

@Getter @Setter
private CacheArgs cacheArgs;

/**
*/
public void installFromModpackZip(Path modpackZip, String slug) {
Expand Down Expand Up @@ -214,7 +218,8 @@ void install(String slug, InstallationEntryPoint entryPoint) {
}

try (
final ApiCaching apiCaching = disableApiCaching ? new DisabledApiCaching() : new ApiCachingImpl(outputDir, CACHING_NAMESPACE);
final ApiCaching apiCaching = disableApiCaching ? new ApiCachingDisabled()
: new ApiCachingImpl(outputDir, CACHING_NAMESPACE, cacheArgs);
final CurseForgeApiClient cfApi = new CurseForgeApiClient(
apiBaseUrl, apiKey, sharedFetchOptions,
CurseForgeApiClient.MINECRAFT_GAME_ID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
import me.itzg.helpers.McImageHelper;
import me.itzg.helpers.cache.CacheArgs;
import me.itzg.helpers.curseforge.ModpacksPageUrlParser.Parsed;
import me.itzg.helpers.files.ResultsFileWriter;
import me.itzg.helpers.files.TabularOutput;
Expand Down Expand Up @@ -163,6 +164,9 @@ static class Listed {
@Option(names = "--disable-api-caching", defaultValue = "${env:CF_DISABLE_API_CACHING:-false}")
boolean disableApiCaching;

@ArgGroup(exclusive = false)
CacheArgs cacheArgs;

@Override
public Integer call() throws Exception {
// https://www.curseforge.com/minecraft/modpacks/all-the-mods-8/files
Expand Down Expand Up @@ -198,7 +202,8 @@ public Integer call() throws Exception {
.setSharedFetchOptions(sharedFetchArgs.options())
.setApiKey(apiKey)
.setDownloadsRepo(downloadsRepo)
.setDisableApiCaching(disableApiCaching);
.setDisableApiCaching(disableApiCaching)
.setCacheArgs(cacheArgs);

if (apiBaseUrl != null) {
installer.setApiBaseUrl(apiBaseUrl);
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/me/itzg/helpers/modrinth/ModrinthApiClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ public Mono<Version> resolveProjectVersion(Project project, ProjectRef projectRe
.flatMap(versions ->
Mono.justOrEmpty(versions.stream()
.filter(version ->
version.getVersionNumber().equals(projectRef.getVersionName())
|| version.getName().equals(projectRef.getVersionName())
version.getVersionNumber().equals(projectRef.getVersionNumber())
|| version.getName().equals(projectRef.getVersionNumber())
)
.findFirst()
));
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/me/itzg/helpers/modrinth/ProjectRef.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class ProjectRef {
private final URI projectUri;
private final VersionType versionType;
private final String versionId;
private final String versionName;
private final String versionNumber;

public static ProjectRef parse(String projectRef) {
final Matcher m = PROJECT_REF.matcher(projectRef);
Expand Down Expand Up @@ -67,16 +67,16 @@ public ProjectRef(String projectSlug, @Nullable String version, boolean datapack
if (this.versionType == null) {
if (isVersionId(version)) {
this.versionId = version;
this.versionName = null;
this.versionNumber = null;
}
else {
this.versionId = null;
this.versionName = version;
this.versionNumber = version;
}
}
else {
this.versionId = null;
this.versionName = null;
this.versionNumber = null;
}
}

Expand All @@ -88,7 +88,7 @@ public ProjectRef(URI projectUri, String versionId) {
this.idOrSlug = filename.endsWith(".mrpack") ?
filename.substring(0, filename.length() - ".mrpack".length()) : filename;

this.versionName = null;
this.versionNumber = null;
this.versionType = null;
this.versionId = versionId;
}
Expand Down Expand Up @@ -138,7 +138,7 @@ public static ProjectRef fromPossibleUrl(
}

public boolean hasVersionName() {
return versionName != null;
return versionNumber != null;
}

public boolean hasVersionType() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
import java.util.Collections;
import me.itzg.helpers.files.DisabledApiCaching;
import me.itzg.helpers.cache.ApiCachingDisabled;
import me.itzg.helpers.http.SharedFetch.Options;
import org.intellij.lang.annotations.Language;
import org.junit.jupiter.api.Test;
Expand All @@ -26,7 +26,7 @@ void apiKeyHeaderIsTrimmed(WireMockRuntimeInfo wmInfo) {

final CategoryInfo result;
try (CurseForgeApiClient client = new CurseForgeApiClient(wmInfo.getHttpBaseUrl(), "key\n", Options.builder().build(),
"test", new DisabledApiCaching()
"test", new ApiCachingDisabled()
)) {
result = client.loadCategoryInfo(Collections.singleton("mc-mods"))
.block();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
import me.itzg.helpers.cache.ApiCachingDisabled;
import me.itzg.helpers.curseforge.model.CurseForgeFile;
import me.itzg.helpers.curseforge.model.ModLoaderType;
import me.itzg.helpers.files.DisabledApiCaching;
import me.itzg.helpers.http.SharedFetch.Options;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
Expand Down Expand Up @@ -53,7 +53,7 @@ public static Stream<Arguments> testMcModsRefsArgs() {
void testMcModsRefs(String ref, String defaultCategory, String gameVersion, ModLoaderType modLoader, ModFileIds expected) {

final CurseForgeApiClient apiClient = new CurseForgeApiClient(wm.baseUrl(), "testing", Options.builder().build(),
CurseForgeApiClient.MINECRAFT_GAME_ID, new DisabledApiCaching()
CurseForgeApiClient.MINECRAFT_GAME_ID, new ApiCachingDisabled()
);

final CategoryInfo categoryInfo = apiClient.loadCategoryInfo(
Expand Down
10 changes: 5 additions & 5 deletions src/test/java/me/itzg/helpers/modrinth/ProjectRefTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void testProjectRefHasVersionNameForOtherValues() {
projectRefUT = new ProjectRef(
this.expectedSlug, this.expectedVersionName);

assertThat(projectRefUT.getVersionName())
assertThat(projectRefUT.getVersionNumber())
.isEqualTo(expectedVersionName);
assertThat(projectRefUT.hasVersionId()).isFalse();
assertThat(projectRefUT.hasVersionType()).isFalse();
Expand All @@ -74,7 +74,7 @@ void fromPossibleUrlDefaultsToGeneratingRefWithPassedValues() {

assertThat(projectRefUT.getIdOrSlug())
.isEqualTo(this.expectedSlug);
assertThat(projectRefUT.getVersionName())
assertThat(projectRefUT.getVersionNumber())
.isEqualTo(expectedVersionName);
}

Expand All @@ -88,7 +88,7 @@ void fromPossibleUrlExtractsProjectSlugFromUrl() {

assertThat(projectRefUT.getIdOrSlug())
.isEqualTo(this.expectedSlug);
assertThat(projectRefUT.getVersionName())
assertThat(projectRefUT.getVersionNumber())
.isEqualTo(expectedVersionName);
}

Expand All @@ -102,7 +102,7 @@ void fromPossibleUrlExtractsProjectVersionFromUrlWhenPresent() {

assertThat(projectRefUT.getIdOrSlug())
.isEqualTo(this.expectedSlug);
assertThat(projectRefUT.getVersionName())
assertThat(projectRefUT.getVersionNumber())
.isEqualTo(expectedVersionName);
}

Expand Down Expand Up @@ -144,7 +144,7 @@ void parseProjectRef(String input, String slugId, VersionType versionType, Strin
assertThat(result.getIdOrSlug()).isEqualTo(slugId);
assertThat(result.getVersionType()).isEqualTo(versionType);
assertThat(result.getVersionId()).isEqualTo(versionId);
assertThat(result.getVersionName()).isEqualTo(versionName);
assertThat(result.getVersionNumber()).isEqualTo(versionName);
assertThat(result.isDatapack()).isEqualTo(datapack);
}

Expand Down