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
Expand Up @@ -47,6 +47,7 @@
import me.itzg.helpers.forge.ForgeInstaller;
import me.itzg.helpers.http.Fetch;
import me.itzg.helpers.http.SharedFetch;
import me.itzg.helpers.http.SharedFetch.Options;
import me.itzg.helpers.http.UriBuilder;
import me.itzg.helpers.json.ObjectMappers;
import reactor.core.publisher.Flux;
Expand Down Expand Up @@ -94,6 +95,9 @@ public class CurseForgeInstaller {
@Getter @Setter
private boolean overridesSkipExisting;

@Getter @Setter
private SharedFetch.Options sharedFetchOptions;

private final Set<String> applicableClassIdSlugs = new HashSet<>(Arrays.asList(
"mc-mods",
"bukkit-plugins",
Expand All @@ -106,14 +110,17 @@ public void install(String slug, String fileMatcher, Integer fileId) throws IOEx

final UriBuilder uriBuilder = UriBuilder.withBaseUrl(apiBaseUrl);

try (SharedFetch preparedFetch = Fetch.sharedFetch("install-curseforge")) {
try (SharedFetch preparedFetch = Fetch.sharedFetch("install-curseforge",
sharedFetchOptions != null ? sharedFetchOptions : Options.builder().build()
)) {
// TODO encapsulate preparedFetch and uriBuilder to avoid passing deep into call tree

final CategoryInfo categoryInfo = loadCategoryInfo(preparedFetch, uriBuilder);

final ModsSearchResponse searchResponse = preparedFetch.fetch(
uriBuilder.resolve("/mods/search?gameId={gameId}&slug={slug}&classId={classId}",
MINECRAFT_GAME_ID, slug, categoryInfo.modpackClassId)
MINECRAFT_GAME_ID, slug, categoryInfo.modpackClassId
)
)
.toObject(ModsSearchResponse.class)
.execute();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import me.itzg.helpers.files.ResultsFileWriter;
import me.itzg.helpers.http.PathOrUri;
import me.itzg.helpers.http.PathOrUriConverter;
import me.itzg.helpers.http.SharedFetchArgs;
import me.itzg.helpers.json.ObjectMappers;
import picocli.CommandLine.ArgGroup;
import picocli.CommandLine.Command;
Expand Down Expand Up @@ -98,6 +99,9 @@ static class Listed {
)
boolean overridesSkipExisting;

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

private static final Pattern PAGE_URL_PATTERN = Pattern.compile(
"https://www.curseforge.com/minecraft/modpacks/(?<slug>.+?)(/files(/(?<fileId>\\d+)?)?)?");

Expand Down Expand Up @@ -133,7 +137,9 @@ public Integer call() throws Exception {
.setForceSynchronize(forceSynchronize)
.setParallelism(parallelDownloads)
.setLevelFrom(levelFrom)
.setOverridesSkipExisting(overridesSkipExisting);
.setOverridesSkipExisting(overridesSkipExisting)
.setSharedFetchOptions(sharedFetchArgs.options());

installer.install(slug, filenameMatcher, fileId);

return ExitCode.OK;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import me.itzg.helpers.files.ResultsFileWriter;
import me.itzg.helpers.http.FailedRequestException;
import me.itzg.helpers.http.SharedFetch;
import me.itzg.helpers.http.SharedFetch.Options;
import me.itzg.helpers.http.UriBuilder;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
Expand Down Expand Up @@ -56,7 +57,7 @@ public Path installUsingVersions(@NonNull String minecraftVersion, String loader

final UriBuilder uriBuilder = UriBuilder.withBaseUrl(fabricMetaBaseUrl);

try (SharedFetch sharedFetch = sharedFetch("fabric")) {
try (SharedFetch sharedFetch = sharedFetch("fabric", Options.builder().build())) {
loaderVersion = resolveLoaderVersion(uriBuilder, sharedFetch, minecraftVersion, loaderVersion);

installerVersion = resolveInstallerVersion(uriBuilder, sharedFetch, installerVersion);
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/me/itzg/helpers/http/Fetch.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package me.itzg.helpers.http;

import java.net.URI;
import me.itzg.helpers.http.SharedFetch.Options;

public class Fetch {

Expand All @@ -15,8 +16,8 @@ public static FetchBuilderBase<?> fetch(URI uri) {
* Provides an efficient way to make multiple web requests since a single client
* is shared.
*/
public static SharedFetch sharedFetch(String forCommand) {
return new SharedFetch(forCommand);
public static SharedFetch sharedFetch(String forCommand, Options options) {
return new SharedFetch(forCommand, options);
}

private Fetch() {
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/me/itzg/helpers/http/FetchBuilderBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.function.BiConsumer;
import lombok.extern.slf4j.Slf4j;
import me.itzg.helpers.errors.GenericException;
import me.itzg.helpers.http.SharedFetch.Options;
import me.itzg.helpers.json.ObjectMappers;
import org.slf4j.Logger;
import reactor.core.publisher.Mono;
Expand Down Expand Up @@ -128,7 +129,7 @@ protected <R> R useReactiveClient(ReactiveClientUser<R> user) {
return user.use(state.sharedFetch.getReactiveClient());
}
else {
try (SharedFetch sharedFetch = new SharedFetch(state.userAgentCommand)) {
try (SharedFetch sharedFetch = new SharedFetch(state.userAgentCommand, Options.builder().build())) {
return user.use(sharedFetch.getReactiveClient());
}
}
Expand Down
28 changes: 27 additions & 1 deletion src/main/java/me/itzg/helpers/http/SharedFetch.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@

import io.netty.handler.codec.http.HttpHeaderNames;
import java.net.URI;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import lombok.Builder;
import lombok.Builder.Default;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import me.itzg.helpers.McImageHelper;
import reactor.netty.http.Http11SslContextSpec;
import reactor.netty.http.client.HttpClient;

/**
Expand All @@ -29,7 +33,7 @@ public class SharedFetch implements AutoCloseable {
@Getter
private final HttpClient reactiveClient;

public SharedFetch(String forCommand) {
public SharedFetch(String forCommand, Options options) {
final String userAgent = String.format("%s/%s (cmd=%s)",
"mc-image-helper",
McImageHelper.getVersion(),
Expand All @@ -43,6 +47,13 @@ public SharedFetch(String forCommand) {
headers
.set(HttpHeaderNames.USER_AGENT.toString(), userAgent)
.set("x-fetch-session", fetchSessionId)
)
// Reference https://projectreactor.io/docs/netty/release/reference/index.html#response-timeout
.responseTimeout(options.getResponseTimeout())
// Reference https://projectreactor.io/docs/netty/release/reference/index.html#ssl-tls-timeout
.secure(spec ->
spec.sslContext(Http11SslContextSpec.forClient())
.handshakeTimeout(options.getTlsHandshakeTimeout())
);

headers.put("x-fetch-session", fetchSessionId);
Expand All @@ -61,4 +72,19 @@ public SharedFetch addHeader(String name, String value) {
@Override
public void close() {
}

@Builder
@Getter
public static class Options {

@Default
private final Duration responseTimeout
// not set by default
= Duration.ofSeconds(5);

@Default
private final Duration tlsHandshakeTimeout
// double the Netty default
= Duration.ofSeconds(20);
}
}
26 changes: 26 additions & 0 deletions src/main/java/me/itzg/helpers/http/SharedFetchArgs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package me.itzg.helpers.http;

import java.time.Duration;
import me.itzg.helpers.http.SharedFetch.Options;
import picocli.CommandLine.Option;

public class SharedFetchArgs {

private final Options.OptionsBuilder optionsBuilder = Options.builder();

@Option(names = "--http-response-timeout", defaultValue = "${env:FETCH_RESPONSE_TIMEOUT}",
description = "The response timeout to apply to HTTP operations. Parsed from ISO-8601 format."
)
public void setResponseTimeout(Duration timeout) {
optionsBuilder.responseTimeout(timeout);
}

@Option(names = "--tls-handshake-timeout", defaultValue = "${env:FETCH_TLS_HANDSHAKE_TIMEOUT}")
public void setTlsHandshakeTimeout(Duration timeout) {
optionsBuilder.tlsHandshakeTimeout(timeout);
}

public Options options() {
return optionsBuilder.build();
}
}
2 changes: 1 addition & 1 deletion src/test/java/me/itzg/helpers/env/InterpolatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ void typicalReplacements() throws IOException {
}

@Test
void interpolateToValueWithDollarSignInValue() throws IOException {
void interpolateToValueWithDollarSign() throws IOException {
when(varProvider.get("CFG_HAS_DOLLAR_VALUE_FILE"))
.thenReturn(null);
when(varProvider.get("CFG_HAS_DOLLAR_VALUE"))
Expand Down