Skip to content

Commit 232bed5

Browse files
authored
cf: API cache duration default is 2 days and can be configured (#482)
1 parent b5a4ecc commit 232bed5

File tree

14 files changed

+87
-36
lines changed

14 files changed

+87
-36
lines changed

src/main/java/me/itzg/helpers/files/ApiCaching.java renamed to src/main/java/me/itzg/helpers/cache/ApiCaching.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package me.itzg.helpers.files;
1+
package me.itzg.helpers.cache;
22

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

src/main/java/me/itzg/helpers/files/DisabledApiCaching.java renamed to src/main/java/me/itzg/helpers/cache/ApiCachingDisabled.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
package me.itzg.helpers.files;
1+
package me.itzg.helpers.cache;
22

33
import java.io.IOException;
44
import reactor.core.publisher.Mono;
55

6-
public class DisabledApiCaching implements ApiCaching {
6+
public class ApiCachingDisabled implements ApiCaching {
77

88
@Override
99
public <R> Mono<R> cache(String operation, Class<R> returnType, Mono<R> resolver, Object... keys) {

src/main/java/me/itzg/helpers/files/ApiCachingImpl.java renamed to src/main/java/me/itzg/helpers/cache/ApiCachingImpl.java

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
package me.itzg.helpers.files;
1+
package me.itzg.helpers.cache;
22

33
import com.fasterxml.jackson.databind.ObjectMapper;
44
import java.io.IOException;
55
import java.nio.file.Files;
66
import java.nio.file.Path;
77
import java.time.Duration;
88
import java.time.Instant;
9+
import java.time.temporal.TemporalAmount;
910
import java.util.HashMap;
1011
import java.util.Iterator;
1112
import java.util.Map;
@@ -14,9 +15,10 @@
1415
import java.util.stream.Stream;
1516
import lombok.Setter;
1617
import lombok.extern.slf4j.Slf4j;
17-
import me.itzg.helpers.files.CacheIndex.CacheEntry;
18+
import me.itzg.helpers.cache.CacheIndex.CacheEntry;
1819
import me.itzg.helpers.json.ObjectMappers;
1920
import org.jetbrains.annotations.Blocking;
21+
import org.jetbrains.annotations.Nullable;
2022
import reactor.core.publisher.Mono;
2123
import reactor.core.scheduler.Schedulers;
2224

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

3234
@Setter
33-
private Duration cacheDuration = Duration.ofHours(24);
35+
private Duration defaultCacheDuration = Duration.ofHours(48);
36+
37+
@Setter
38+
private Map<String/*operation*/,Duration> cacheDurations = new HashMap<>();
3439

3540
@Blocking
36-
public ApiCachingImpl(Path outputDirectory, String namespace) throws IOException {
41+
public ApiCachingImpl(Path outputDirectory, String namespace, @Nullable CacheArgs cacheArgs) throws IOException {
42+
if (cacheArgs != null) {
43+
defaultCacheDuration = cacheArgs.getDefaultCacheDuration();
44+
cacheDurations = cacheArgs.getCacheDurations();
45+
}
3746
objectMapper = ObjectMappers.defaultMapper();
3847
cacheNamespaceDir = outputDirectory.resolve(CACHE_SUBIDR).resolve(namespace);
3948
cacheIndex = loadCacheIndex();
@@ -110,7 +119,9 @@ private <R> Mono<R> saveToCache(String operation, String keys, R value) {
110119
synchronized (cacheIndex) {
111120
cacheIndex.getOperations().computeIfAbsent(operation, s -> new HashMap<>())
112121
.put(keys, new CacheEntry()
113-
.setExpiresAt(Instant.now().plus(cacheDuration))
122+
.setExpiresAt(Instant.now().plus(
123+
lookupCacheDuration(operation)
124+
))
114125
.setFilename(filename)
115126
);
116127
}
@@ -126,6 +137,12 @@ private <R> Mono<R> saveToCache(String operation, String keys, R value) {
126137
.subscribeOn(Schedulers.boundedElastic());
127138
}
128139

140+
private TemporalAmount lookupCacheDuration(String operation) {
141+
return cacheDurations != null ?
142+
cacheDurations.getOrDefault(operation, defaultCacheDuration)
143+
: defaultCacheDuration;
144+
}
145+
129146
private <R> Mono<R> loadFromCache(String operation, String keys, CacheEntry entry, Class<R> returnType) {
130147

131148
return Mono.fromCallable(() -> {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package me.itzg.helpers.cache;
2+
3+
import java.time.Duration;
4+
import java.util.Map;
5+
import lombok.Data;
6+
import picocli.CommandLine.Option;
7+
8+
@Data
9+
public class CacheArgs {
10+
@Option(names = "--api-cache-ttl", paramLabel = "OPERATION=DURATION",
11+
description = "Set individual operation TTLs"
12+
)
13+
Map<String, Duration> cacheDurations;
14+
15+
@Option(names = "--api-cache-default-ttl", defaultValue = "P2D", paramLabel = "DURATION",
16+
description = "Set default/fallback TTL in ISO-8601 duration format.\nDefault: ${DEFAULT-VALUE}"
17+
)
18+
Duration defaultCacheDuration;
19+
}

src/main/java/me/itzg/helpers/files/CacheIndex.java renamed to src/main/java/me/itzg/helpers/cache/CacheIndex.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package me.itzg.helpers.files;
1+
package me.itzg.helpers.cache;
22

33
import java.time.Instant;
44
import java.util.HashMap;

src/main/java/me/itzg/helpers/curseforge/CurseForgeApiClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.util.HashMap;
1111
import java.util.Map;
1212
import lombok.extern.slf4j.Slf4j;
13+
import me.itzg.helpers.cache.ApiCaching;
1314
import me.itzg.helpers.curseforge.model.Category;
1415
import me.itzg.helpers.curseforge.model.CurseForgeFile;
1516
import me.itzg.helpers.curseforge.model.CurseForgeMod;
@@ -21,7 +22,6 @@
2122
import me.itzg.helpers.curseforge.model.ModsSearchResponse;
2223
import me.itzg.helpers.errors.GenericException;
2324
import me.itzg.helpers.errors.InvalidParameterException;
24-
import me.itzg.helpers.files.ApiCaching;
2525
import me.itzg.helpers.http.FailedRequestException;
2626
import me.itzg.helpers.http.Fetch;
2727
import me.itzg.helpers.http.FileDownloadStatusHandler;

src/main/java/me/itzg/helpers/curseforge/CurseForgeFilesCommand.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
import java.util.concurrent.Callable;
1616
import java.util.stream.Collectors;
1717
import lombok.extern.slf4j.Slf4j;
18+
import me.itzg.helpers.cache.ApiCaching;
19+
import me.itzg.helpers.cache.ApiCachingDisabled;
20+
import me.itzg.helpers.cache.ApiCachingImpl;
21+
import me.itzg.helpers.cache.CacheArgs;
1822
import me.itzg.helpers.curseforge.CurseForgeFilesManifest.FileEntry;
1923
import me.itzg.helpers.curseforge.model.Category;
2024
import me.itzg.helpers.curseforge.model.CurseForgeFile;
@@ -24,9 +28,6 @@
2428
import me.itzg.helpers.curseforge.model.ModLoaderType;
2529
import me.itzg.helpers.errors.GenericException;
2630
import me.itzg.helpers.errors.InvalidParameterException;
27-
import me.itzg.helpers.files.ApiCaching;
28-
import me.itzg.helpers.files.ApiCachingImpl;
29-
import me.itzg.helpers.files.DisabledApiCaching;
3031
import me.itzg.helpers.files.Manifests;
3132
import me.itzg.helpers.http.SharedFetchArgs;
3233
import org.jetbrains.annotations.NotNull;
@@ -99,6 +100,9 @@ public void setSlugCategory(String defaultCategory) {
99100
@Option(names = "--disable-api-caching", defaultValue = "${env:CF_DISABLE_API_CACHING:-false}")
100101
boolean disableApiCaching;
101102

103+
@ArgGroup(exclusive = false)
104+
CacheArgs cacheArgs;
105+
102106
@ArgGroup(exclusive = false)
103107
SharedFetchArgs sharedFetchArgs = new SharedFetchArgs();
104108

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

124128
if (modFileRefs != null && !modFileRefs.isEmpty()) {
125129
try (
126-
final ApiCaching apiCaching = disableApiCaching ? new DisabledApiCaching() : new ApiCachingImpl(outputDir, CACHING_NAMESPACE);
130+
final ApiCaching apiCaching = disableApiCaching ? new ApiCachingDisabled()
131+
: new ApiCachingImpl(outputDir, CACHING_NAMESPACE, cacheArgs);
127132
final CurseForgeApiClient apiClient = new CurseForgeApiClient(
128133
apiBaseUrl, apiKey, sharedFetchArgs.options(),
129134
CurseForgeApiClient.MINECRAFT_GAME_ID,

src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
import lombok.RequiredArgsConstructor;
3333
import lombok.Setter;
3434
import lombok.extern.slf4j.Slf4j;
35+
import me.itzg.helpers.cache.ApiCaching;
36+
import me.itzg.helpers.cache.ApiCachingDisabled;
37+
import me.itzg.helpers.cache.ApiCachingImpl;
38+
import me.itzg.helpers.cache.CacheArgs;
3539
import me.itzg.helpers.curseforge.ExcludeIncludesContent.ExcludeIncludes;
3640
import me.itzg.helpers.curseforge.OverridesApplier.Result;
3741
import me.itzg.helpers.curseforge.model.Category;
@@ -45,9 +49,6 @@
4549
import me.itzg.helpers.errors.InvalidParameterException;
4650
import me.itzg.helpers.errors.RateLimitException;
4751
import me.itzg.helpers.fabric.FabricLauncherInstaller;
48-
import me.itzg.helpers.files.ApiCaching;
49-
import me.itzg.helpers.files.ApiCachingImpl;
50-
import me.itzg.helpers.files.DisabledApiCaching;
5152
import me.itzg.helpers.files.Manifests;
5253
import me.itzg.helpers.files.ResultsFileWriter;
5354
import me.itzg.helpers.forge.ForgeInstaller;
@@ -134,6 +135,9 @@ public class CurseForgeInstaller {
134135
@Getter @Setter
135136
private boolean disableApiCaching;
136137

138+
@Getter @Setter
139+
private CacheArgs cacheArgs;
140+
137141
/**
138142
*/
139143
public void installFromModpackZip(Path modpackZip, String slug) {
@@ -214,7 +218,8 @@ void install(String slug, InstallationEntryPoint entryPoint) {
214218
}
215219

216220
try (
217-
final ApiCaching apiCaching = disableApiCaching ? new DisabledApiCaching() : new ApiCachingImpl(outputDir, CACHING_NAMESPACE);
221+
final ApiCaching apiCaching = disableApiCaching ? new ApiCachingDisabled()
222+
: new ApiCachingImpl(outputDir, CACHING_NAMESPACE, cacheArgs);
218223
final CurseForgeApiClient cfApi = new CurseForgeApiClient(
219224
apiBaseUrl, apiKey, sharedFetchOptions,
220225
CurseForgeApiClient.MINECRAFT_GAME_ID,

src/main/java/me/itzg/helpers/curseforge/InstallCurseForgeCommand.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import java.util.stream.Collectors;
1414
import java.util.stream.Stream;
1515
import me.itzg.helpers.McImageHelper;
16+
import me.itzg.helpers.cache.CacheArgs;
1617
import me.itzg.helpers.curseforge.ModpacksPageUrlParser.Parsed;
1718
import me.itzg.helpers.files.ResultsFileWriter;
1819
import me.itzg.helpers.files.TabularOutput;
@@ -163,6 +164,9 @@ static class Listed {
163164
@Option(names = "--disable-api-caching", defaultValue = "${env:CF_DISABLE_API_CACHING:-false}")
164165
boolean disableApiCaching;
165166

167+
@ArgGroup(exclusive = false)
168+
CacheArgs cacheArgs;
169+
166170
@Override
167171
public Integer call() throws Exception {
168172
// https://www.curseforge.com/minecraft/modpacks/all-the-mods-8/files
@@ -198,7 +202,8 @@ public Integer call() throws Exception {
198202
.setSharedFetchOptions(sharedFetchArgs.options())
199203
.setApiKey(apiKey)
200204
.setDownloadsRepo(downloadsRepo)
201-
.setDisableApiCaching(disableApiCaching);
205+
.setDisableApiCaching(disableApiCaching)
206+
.setCacheArgs(cacheArgs);
202207

203208
if (apiBaseUrl != null) {
204209
installer.setApiBaseUrl(apiBaseUrl);

src/main/java/me/itzg/helpers/modrinth/ModrinthApiClient.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ public Mono<Version> resolveProjectVersion(Project project, ProjectRef projectRe
133133
.flatMap(versions ->
134134
Mono.justOrEmpty(versions.stream()
135135
.filter(version ->
136-
version.getVersionNumber().equals(projectRef.getVersionName())
137-
|| version.getName().equals(projectRef.getVersionName())
136+
version.getVersionNumber().equals(projectRef.getVersionNumber())
137+
|| version.getName().equals(projectRef.getVersionNumber())
138138
)
139139
.findFirst()
140140
));

0 commit comments

Comments
 (0)