33import static pl .skidam .automodpack_core .Constants .*;
44
55import java .io .*;
6+ import java .net .HttpURLConnection ;
67import java .nio .charset .StandardCharsets ;
78import java .nio .file .Files ;
89import java .nio .file .Path ;
1314
1415import pl .skidam .automodpack_core .protocol .DownloadClient ;
1516import pl .skidam .automodpack_core .utils .CustomThreadFactoryBuilder ;
17+ import pl .skidam .automodpack_core .utils .DownloadSource ;
1618import pl .skidam .automodpack_core .utils .FileInspection ;
1719import pl .skidam .automodpack_core .utils .HashUtils ;
1820import pl .skidam .automodpack_core .utils .SmartFileUtils ;
@@ -56,11 +58,11 @@ public void attachDownloadClient(DownloadClient downloadClient) {
5658 this .downloadClient = downloadClient ;
5759 }
5860
59- public synchronized void download (Path file , String sha1 , List <String > urls , long fileSize , Runnable successCallback , Runnable failureCallback ) {
61+ public synchronized void download (Path file , String sha1 , List <DownloadSource > sources , long fileSize , Runnable successCallback , Runnable failureCallback ) {
6062 FileInspection .HashPathPair hashPathPair = new FileInspection .HashPathPair (sha1 , file );
6163 if (queuedDownloads .containsKey (hashPathPair )) return ;
6264
63- QueuedDownload task = new QueuedDownload (file , urls , fileSize , 0 , successCallback , failureCallback );
65+ QueuedDownload task = new QueuedDownload (file , sources , fileSize , 0 , successCallback , failureCallback );
6466 queuedDownloads .put (hashPathPair , task );
6567 totalFilesAdded ++;
6668 downloadNext ();
@@ -199,12 +201,9 @@ private synchronized void downloadNext() {
199201 }
200202
201203 private String predictSource (QueuedDownload task ) {
202- int numberOfIndexes = task .urls .size ();
203- int urlIndex = Math .min (task .attempts / MAX_DOWNLOAD_ATTEMPTS , numberOfIndexes );
204- if (task .urls .size () > urlIndex ) {
205- String url = task .urls .get (urlIndex );
206- if (!Objects .equals (url , "host" )) { return getDomainFromUrl (url ); }
207- }
204+ int numberOfIndexes = task .sources .size ();
205+ int sourceIndex = Math .min (task .attempts / MAX_DOWNLOAD_ATTEMPTS , numberOfIndexes );
206+ if (task .sources .size () > sourceIndex ) { return getDomainFromUrl (task .sources .get (sourceIndex ).url ()); }
208207 return "internal_client" ;
209208 }
210209
@@ -248,14 +247,14 @@ private void processDownloadTask(FileInspection.HashPathPair hashPathPair, Queue
248247 }
249248
250249 private boolean attemptDownload (FileInspection .HashPathPair hashPathPair , QueuedDownload task , Path storeFile ) throws InterruptedException {
251- int numberOfIndexes = task .urls .size ();
252- int urlIndex = Math .min (task .attempts / MAX_DOWNLOAD_ATTEMPTS , numberOfIndexes );
253- String url = (task .urls .size () > urlIndex ) ? task .urls .get (urlIndex ) : null ;
250+ int numberOfIndexes = task .sources .size ();
251+ int sourceIndex = Math .min (task .attempts / MAX_DOWNLOAD_ATTEMPTS , numberOfIndexes );
252+ DownloadSource source = (task .sources .size () > sourceIndex ) ? task .sources .get (sourceIndex ) : null ;
254253 Path tempStoreFile = storeDir .resolve (hashPathPair .hash () + ".tmp" );
255254
256255 try {
257- if (url != null && ! Objects . equals ( url , "host" ) && task .attempts < MAX_DOWNLOAD_ATTEMPTS * numberOfIndexes ) {
258- httpDownloader .download (url , tempStoreFile , this ::updateNetworkProgress );
256+ if (source != null && task .attempts < MAX_DOWNLOAD_ATTEMPTS * numberOfIndexes ) {
257+ httpDownloader .download (source , tempStoreFile , this ::updateNetworkProgress );
259258 } else if (downloadClient != null ) {
260259 hostDownloadFile (hashPathPair , tempStoreFile , this ::updateNetworkProgress );
261260 } else {
@@ -270,6 +269,13 @@ private boolean attemptDownload(FileInspection.HashPathPair hashPathPair, Queued
270269 SmartFileUtils .executeOrder66 (tempStoreFile );
271270 return false ;
272271 }
272+ } catch (HttpFileDownloader .HttpStatusException e ) {
273+ if (source != null && source .provider () == DownloadSource .Provider .CURSEFORGE && e .statusCode () == HttpURLConnection .HTTP_UNAUTHORIZED ) {
274+ LOGGER .warn ("CurseForge rejected the download API key with HTTP 401; trying the next source" );
275+ task .attempts = (sourceIndex + 1 ) * MAX_DOWNLOAD_ATTEMPTS - 1 ;
276+ }
277+ SmartFileUtils .executeOrder66 (tempStoreFile );
278+ return false ;
273279 } catch (IOException e ) {
274280 SmartFileUtils .executeOrder66 (tempStoreFile );
275281 return false ;
@@ -314,7 +320,7 @@ private void handleRetry(FileInspection.HashPathPair key, QueuedDownload task, b
314320 }
315321 SmartFileUtils .executeOrder66 (task .file );
316322
317- if (task .attempts < (task .urls .size () + 1 ) * MAX_DOWNLOAD_ATTEMPTS ) {
323+ if (task .attempts < (task .sources .size () + 1 ) * MAX_DOWNLOAD_ATTEMPTS ) {
318324 LOGGER .warn ("Retrying download: {}" , task .file .getFileName ());
319325 task .attempts ++;
320326 queuedDownloads .put (key , task );
@@ -402,15 +408,15 @@ public void setCancelled(boolean cancelled) {
402408
403409 public static class QueuedDownload {
404410 public final Path file ;
405- public final List <String > urls ;
411+ public final List <DownloadSource > sources ;
406412 public final long fileSize ;
407413 public int attempts ;
408414 public final Runnable successCallback ;
409415 public final Runnable failureCallback ;
410416
411- public QueuedDownload (Path f , List <String > u , long size , int a , Runnable s , Runnable fa ) {
417+ public QueuedDownload (Path f , List <DownloadSource > sources , long size , int a , Runnable s , Runnable fa ) {
412418 file = f ;
413- urls = u ;
419+ this . sources = sources ;
414420 fileSize = size ;
415421 attempts = a ;
416422 successCallback = s ;
0 commit comments