Skip to content

Commit f0d51ec

Browse files
authored
cf: remove failed file downloads (#626)
Also * Switch default to http 1.1 * Include retry number in CF file
1 parent db08f8a commit f0d51ec

File tree

4 files changed

+47
-10
lines changed

4 files changed

+47
-10
lines changed

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import me.itzg.helpers.errors.InvalidParameterException;
5151
import me.itzg.helpers.fabric.FabricLauncherInstaller;
5252
import me.itzg.helpers.files.Manifests;
53+
import me.itzg.helpers.files.ReactiveFileUtils;
5354
import me.itzg.helpers.files.ResultsFileWriter;
5455
import me.itzg.helpers.forge.ForgeInstaller;
5556
import me.itzg.helpers.forge.ForgeInstallerResolver;
@@ -763,10 +764,15 @@ private Mono<PathWithInfo> downloadAndPostProcess(
763764
private Mono<DownloadOrResolveResult> buildRetryableDownload(InstallContext context,
764765
CurseForgeMod modInfo, CurseForgeFile cfFile, boolean isWorld, Path outputSubdir
765766
) {
767+
final Path outputFile = resolveOutputFile(outputSubdir, cfFile);
768+
766769
// use defer so that the download mono is rebuilt on each retry
767770
return Mono.defer(() ->
768771
downloadOrResolveFile(context, modInfo, isWorld, outputSubdir, cfFile)
769772
.checkpoint()
773+
.onErrorResume(throwable ->
774+
ReactiveFileUtils.removeFailedDownload(throwable, outputFile)
775+
)
770776
)
771777
// retry the deferred part above if one of the expected failure cases
772778
.retryWhen(
@@ -778,8 +784,10 @@ private Mono<DownloadOrResolveResult> buildRetryableDownload(InstallContext con
778784
throwable instanceof ChannelException
779785
)
780786
.doBeforeRetry(retrySignal ->
781-
log.warn("Retrying to download {} @ {}:{}",
782-
cfFile.getFileName(), modInfo.getName(), cfFile.getDisplayName()
787+
log.warn("Retry #{} download of {} @ {}:{} due to {}",
788+
retrySignal.totalRetries() + 1,
789+
cfFile.getFileName(), modInfo.getName(), cfFile.getDisplayName(),
790+
retrySignal.failure().getClass().getSimpleName()
783791
)
784792
)
785793
);
@@ -799,7 +807,7 @@ static class DownloadOrResolveResult {
799807
private Mono<DownloadOrResolveResult> downloadOrResolveFile(InstallContext context, CurseForgeMod modInfo,
800808
boolean isWorld, Path outputSubdir, CurseForgeFile cfFile
801809
) {
802-
final Path outputFile = outputSubdir.resolve(cfFile.getFileName());
810+
final Path outputFile = resolveOutputFile(outputSubdir, cfFile);
803811

804812
// Will try to locate an existing file by alternate names that browser might create,
805813
// but only for non-world files of the modpack
@@ -829,6 +837,10 @@ private Mono<DownloadOrResolveResult> downloadOrResolveFile(InstallContext conte
829837
}
830838
}
831839

840+
private static @NotNull Path resolveOutputFile(Path outputSubdir, CurseForgeFile cfFile) {
841+
return outputSubdir.resolve(cfFile.getFileName());
842+
}
843+
832844
/**
833845
* @return Mono.error with {@link FileHashInvalidException} when not valid
834846
*/

src/main/java/me/itzg/helpers/fabric/FabricLauncherInstaller.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,14 @@ public void installUsingVersions(
6666

6767
fabricMetaClient.resolveInstallerVersion(installerVersion)
6868
.doOnNext(v -> log.debug("Resolved installer version {} from {}", v, installerVersion))
69-
.flatMap(resolvedInstallerVersion -> downloadResolvedLauncher(
70-
fabricMetaClient,
71-
resolvedMinecraftVersion,
72-
resolvedLoaderVersion,
73-
resolvedInstallerVersion
74-
))
69+
.flatMap(resolvedInstallerVersion ->
70+
downloadResolvedLauncher(
71+
fabricMetaClient,
72+
resolvedMinecraftVersion,
73+
resolvedLoaderVersion,
74+
resolvedInstallerVersion
75+
)
76+
)
7577
.checkpoint("downloadResolvedLauncher")
7678
)
7779
)

src/main/java/me/itzg/helpers/files/ReactiveFileUtils.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package me.itzg.helpers.files;
22

33
import io.netty.buffer.ByteBuf;
4+
import java.io.IOException;
45
import java.nio.channels.FileChannel;
56
import java.nio.file.Files;
67
import java.nio.file.Path;
@@ -84,4 +85,26 @@ public static Mono<Long> writeByteBufFluxToFile(ByteBufFlux byteBufFlux, Path fi
8485
// Just expose the total bytes read from network
8586
.map(Tuple2::getT2);
8687
}
88+
89+
/**
90+
* Used with {@link reactor.core.publisher.Mono#onErrorResume(java.util.function.Function)}
91+
* @param throwable the throwable to pass to the returned mono
92+
* @param outputFile the file to remove, if present
93+
* @return an error mono with the given throwable as cause
94+
* @param <T> the type of the surrounding reactive chain
95+
*/
96+
public static <T> Mono<T> removeFailedDownload(Throwable throwable, Path outputFile) {
97+
return Mono.<T>create(sink -> {
98+
try {
99+
log.trace("Removing failed download of {}", outputFile);
100+
if (Files.deleteIfExists(outputFile)) {
101+
log.debug("Removed failed download of {}", outputFile);
102+
}
103+
} catch (IOException e) {
104+
log.error("Unable to remove failed download of {}", outputFile, e);
105+
}
106+
sink.error(throwable);
107+
})
108+
.subscribeOn(Schedulers.boundedElastic());
109+
}
87110
}

src/main/java/me/itzg/helpers/http/SharedFetchArgs.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public void setPendingAcquireTimeout(Duration timeout) {
4848
optionsBuilder.pendingAcquireTimeout(timeout);
4949
}
5050

51-
@Option(names = "--use-http2", defaultValue = "${env:FETCH_USE_HTTP2:-true}",
51+
@Option(names = "--use-http2", defaultValue = "${env:FETCH_USE_HTTP2:-false}",
5252
description = "Whether to use HTTP/2. Default: ${DEFAULT-VALUE}"
5353
)
5454
public void setUseHttp2(boolean useHttp2) {

0 commit comments

Comments
 (0)