1313import java .nio .file .Files ;
1414import java .nio .file .Path ;
1515import java .nio .file .Paths ;
16+ import java .time .Duration ;
1617import java .util .Arrays ;
1718import java .util .Collection ;
1819import java .util .Collections ;
5758import reactor .core .publisher .Flux ;
5859import reactor .core .publisher .Mono ;
5960import reactor .core .scheduler .Schedulers ;
61+ import reactor .util .retry .Retry ;
6062
6163@ RequiredArgsConstructor
6264@ Slf4j
@@ -70,6 +72,8 @@ public class CurseForgeInstaller {
7072 public static final String REPO_SUBDIR_MODPACKS = "modpacks" ;
7173 public static final String REPO_SUBDIR_MODS = "mods" ;
7274 public static final String REPO_SUBDIR_WORLDS = "worlds" ;
75+ private static final Duration BAD_FILE_DELAY = Duration .ofSeconds (5 );
76+ public static final int BAD_FILE_ATTEMPTS = 3 ;
7377
7478 private final Path outputDir ;
7579 private final Path resultsFile ;
@@ -734,7 +738,21 @@ else if (category.getSlug().equals("worlds")) {
734738 );
735739
736740 final Mono <ResolveResult > resolvedFileMono =
737- downloadOrResolveFile (context , modInfo , isWorld , outputDir , cfFile );
741+ Mono .defer (() ->
742+ downloadOrResolveFile (context , modInfo , isWorld , outputDir , cfFile )
743+ )
744+ // retry the deferred part above if one of the expected failure cases
745+ .retryWhen (
746+ Retry .fixedDelay (BAD_FILE_ATTEMPTS , BAD_FILE_DELAY )
747+ .filter (throwable ->
748+ throwable instanceof FileHashInvalidException ||
749+ throwable instanceof FailedRequestException
750+ )
751+ .doBeforeRetry (retrySignal ->
752+ log .warn ("Retrying to download {} @ {}:{}" ,
753+ cfFile .getFileName (), projectID , fileID )
754+ )
755+ );
738756
739757 return isWorld ?
740758 resolvedFileMono
@@ -780,10 +798,12 @@ private Mono<ResolveResult> downloadOrResolveFile(InstallContext context, CurseF
780798
781799 if (locatedFile != null ) {
782800 log .info ("Mod file {} already exists" , locatedFile );
783- return Mono .just (new ResolveResult (locatedFile ));
801+ return FileHashVerifier .verify (locatedFile , cfFile .getHashes ())
802+ .map (ResolveResult ::new );
784803 }
785804 else {
786805 return context .cfApi .download (cfFile , outputFile , modFileDownloadStatusHandler (this .outputDir , log ))
806+ .flatMap (path -> FileHashVerifier .verify (path , cfFile .getHashes ()))
787807 .map (ResolveResult ::new )
788808 .onErrorResume (
789809 e -> e instanceof FailedRequestException
0 commit comments