diff --git a/src/main/java/me/itzg/helpers/McImageHelper.java b/src/main/java/me/itzg/helpers/McImageHelper.java index 3ef8c92c..ebb5357b 100644 --- a/src/main/java/me/itzg/helpers/McImageHelper.java +++ b/src/main/java/me/itzg/helpers/McImageHelper.java @@ -239,4 +239,4 @@ public Integer call() throws Exception { return ExitCode.OK; } } -} +} \ No newline at end of file diff --git a/src/main/java/me/itzg/helpers/fabric/FabricMetaClient.java b/src/main/java/me/itzg/helpers/fabric/FabricMetaClient.java index 6489a652..3fc930e3 100644 --- a/src/main/java/me/itzg/helpers/fabric/FabricMetaClient.java +++ b/src/main/java/me/itzg/helpers/fabric/FabricMetaClient.java @@ -19,6 +19,18 @@ public class FabricMetaClient { private final SharedFetch sharedFetch; private final UriBuilder uriBuilder; + + /** + * Retry attempts for metadata, non-downloads + */ + @Setter + private long retryMaxAttempts = 5; + /** + * Retry minimum backoff for metadata, non-downloads + */ + @Setter + private Duration retryMinBackoff = Duration.ofMillis(500); + @Setter private int downloadRetryMaxAttempts = 5; @Setter @@ -59,7 +71,9 @@ else if (isSnapshot(version)) { return findFirst(versionEntries, versionEntry -> versionEntry.getVersion().equalsIgnoreCase(version)) .switchIfEmpty(Mono.error(() -> new GenericException("Unable to find requested version"))); } - }); + }) + .retryWhen(Retry.backoff(retryMaxAttempts, retryMinBackoff).filter(IOException.class::isInstance)) + .checkpoint(); } private static boolean isSnapshot(@Nullable String version) { @@ -91,7 +105,9 @@ public Mono resolveLoaderVersion(String minecraftVersion, String loaderV .getLoader(); return Mono.just(loader.getVersion()); - }); + }) + .retryWhen(Retry.backoff(retryMaxAttempts, retryMinBackoff).filter(IOException.class::isInstance)) + .checkpoint(); } public Mono resolveInstallerVersion(String installerVersion) { @@ -111,7 +127,9 @@ public Mono resolveInstallerVersion(String installerVersion) { .orElseGet( () -> Mono.error(new GenericException("Failed to find stable installer from " + uriBuilder.getBaseUrl())) ) - ); + ) + .retryWhen(Retry.backoff(retryMaxAttempts, retryMinBackoff).filter(IOException.class::isInstance)) + .checkpoint(); } public Mono downloadLauncher( diff --git a/src/main/java/me/itzg/helpers/http/ObjectFetchBuilder.java b/src/main/java/me/itzg/helpers/http/ObjectFetchBuilder.java index 135a9c9c..92368a59 100644 --- a/src/main/java/me/itzg/helpers/http/ObjectFetchBuilder.java +++ b/src/main/java/me/itzg/helpers/http/ObjectFetchBuilder.java @@ -2,17 +2,15 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; +import java.io.IOException; +import java.util.List; import lombok.extern.slf4j.Slf4j; -import me.itzg.helpers.errors.GenericException; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; import reactor.netty.ByteBufMono; import reactor.netty.http.client.HttpClient; import reactor.netty.http.client.HttpClientResponse; -import java.io.IOException; -import java.util.List; - @Slf4j public class ObjectFetchBuilder extends FetchBuilderBase> implements RequestResponseAssembler @@ -84,7 +82,7 @@ private Mono handleResponse(HttpClientResponse resp, ByteBufMono bodyMono try { return Mono.just(reader.readValue(inputStream)); } catch (IOException e) { - return Mono.error(new GenericException( + return Mono.error(new ResponseParsingException( "Failed to parse response body into " + (listOf ? "list of " + type : type), e diff --git a/src/main/java/me/itzg/helpers/http/ResponseParsingException.java b/src/main/java/me/itzg/helpers/http/ResponseParsingException.java new file mode 100644 index 00000000..fa8fd5a6 --- /dev/null +++ b/src/main/java/me/itzg/helpers/http/ResponseParsingException.java @@ -0,0 +1,10 @@ +package me.itzg.helpers.http; + +import java.io.IOException; + +public class ResponseParsingException extends IOException { + + public ResponseParsingException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/me/itzg/helpers/modrinth/ModrinthApiClient.java b/src/main/java/me/itzg/helpers/modrinth/ModrinthApiClient.java index 2904e35d..f2ac807c 100644 --- a/src/main/java/me/itzg/helpers/modrinth/ModrinthApiClient.java +++ b/src/main/java/me/itzg/helpers/modrinth/ModrinthApiClient.java @@ -31,6 +31,9 @@ import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; +/** + * Provides a client for Modrinth Labrinth API + */ @Slf4j public class ModrinthApiClient implements AutoCloseable { diff --git a/src/main/java/me/itzg/helpers/modrinth/model/VersionFile.java b/src/main/java/me/itzg/helpers/modrinth/model/VersionFile.java index 7f647740..113a772d 100644 --- a/src/main/java/me/itzg/helpers/modrinth/model/VersionFile.java +++ b/src/main/java/me/itzg/helpers/modrinth/model/VersionFile.java @@ -3,13 +3,20 @@ import java.util.Map; import lombok.Data; +/** + * Refer to files of getversion + */ @Data public class VersionFile { - Map hashes; - String url; + /** + * key is either sha512 or sha1 + */ + Map hashes; - String filename; + String url; - boolean primary; + String filename; + + boolean primary; }