1- using  Hi3Helper . Http ; 
1+ using  Hi3Helper ; 
2+ using  Hi3Helper . Http ; 
3+ using  Hi3Helper . Http . Legacy ; 
24using  System ; 
35using  System . Collections . Generic ; 
46using  System . IO ; 
57using  System . Linq ; 
8+ using  System . Net ; 
69using  System . Text ; 
710using  System . Threading ; 
811using  System . Threading . Tasks ; 
@@ -23,27 +26,27 @@ public static class FallbackCDNUtil
2326        public  static List < CDNURLProperty >  CDNList  =  new  List < CDNURLProperty > 
2427        { 
2528            new  CDNURLProperty 
26-             { 
27-                 Name  =  "GitHub" , 
28-                 URLPrefix  =  "https://github.com/neon-nyan /CollapseLauncher-ReleaseRepo/raw/main" , 
29-                 PartialDownloadSupport  =  true 
30-             } , 
31-             new  CDNURLProperty 
32-             { 
33-                 Name  =  "Cloudflare" , 
34-                 URLPrefix  =  "https://r2.bagelnl.my.id/cl-cdn" , 
35-                 PartialDownloadSupport  =  true 
36-             } , 
37-             new  CDNURLProperty 
38-             { 
39-                 Name  =  "Bitbucket " , 
40-                 URLPrefix  =  "https://bitbucket.org/neon-nyan/collapselauncher-releaserepo /raw/main" 
41-             } , 
42-             new  CDNURLProperty 
43-             { 
44-                 Name  =  "GitLab " , 
45-                 URLPrefix  =  "https://gitlab.com/bagusnl/CollapseLauncher-ReleaseRepo/-/raw/main /" 
46-             } 
29+                { 
30+                    Name  =  "GitHub" , 
31+                    URLPrefix  =  "https://github.com/CollapseLauncher /CollapseLauncher-ReleaseRepo/raw/main" , 
32+                    PartialDownloadSupport  =  true 
33+                } , 
34+                new  CDNURLProperty 
35+                { 
36+                    Name  =  "Cloudflare" , 
37+                    URLPrefix  =  "https://r2.bagelnl.my.id/cl-cdn" , 
38+                    PartialDownloadSupport  =  true 
39+                } , 
40+                new  CDNURLProperty 
41+                { 
42+                    Name  =  "GitLab " , 
43+                    URLPrefix  =  "https://gitlab.com/bagusnl/CollapseLauncher-ReleaseRepo/- /raw/main/ " 
44+                } , 
45+                new  CDNURLProperty 
46+                { 
47+                    Name  =  "Coding " , 
48+                    URLPrefix  =  "https://ohly-generic.pkg.coding.net/collapse/release /" 
49+                } , 
4750        } ; 
4851
4952        public  static event  EventHandler < DownloadEvent >  DownloadProgress ; 
@@ -76,6 +79,34 @@ public static async Task DownloadCDNFallbackContent(Http httpInstance, string ou
7679            } 
7780        } 
7881
82+         public  static async  Task  DownloadCDNFallbackContent ( DownloadClient  downloadClient ,  string  outputPath ,  int  parallelThread ,  string  relativeURL ,  CancellationToken  token ) 
83+         { 
84+             // Get the preferred CDN first and try get the content 
85+             CDNURLProperty  preferredCDN  =  GetPreferredCDN ( ) ; 
86+             bool  isSuccess  =  await  TryGetCDNContent ( preferredCDN ,  downloadClient ,  outputPath ,  relativeURL ,  parallelThread ,  token ) ; 
87+ 
88+             // If successful, then return 
89+             if  ( isSuccess )  return ; 
90+ 
91+             // If the fail return code occurred by the token, then throw cancellation exception 
92+             token . ThrowIfCancellationRequested ( ) ; 
93+ 
94+             // If not, then continue to get the content from another CDN 
95+             foreach  ( CDNURLProperty  fallbackCDN  in  CDNList . Where ( x =>  ! x . Equals ( preferredCDN ) ) ) 
96+             { 
97+                 isSuccess  =  await  TryGetCDNContent ( fallbackCDN ,  downloadClient ,  outputPath ,  relativeURL ,  parallelThread ,  token ) ; 
98+ 
99+                 // If successful, then return 
100+                 if  ( isSuccess )  return ; 
101+             } 
102+ 
103+             // If all of them failed, then throw an exception 
104+             if  ( ! isSuccess ) 
105+             { 
106+                 throw  new  AggregateException ( $ "All available CDNs aren't reachable for your network while getting content: { relativeURL } . Please check your internet!") ; 
107+             } 
108+         } 
109+ 
79110        public  static async  Task  DownloadCDNFallbackContent ( Http  httpInstance ,  Stream  outputStream ,  string  relativeURL ,  CancellationToken  token ) 
80111        { 
81112            // Argument check 
@@ -147,6 +178,88 @@ private static async Task<bool> TryGetCDNContent(CDNURLProperty cdnProp, Http ht
147178            } 
148179        } 
149180
181+         public  static async  Task  DownloadCDNFallbackContent ( DownloadClient  downloadClient ,  Stream  outputStream ,  string  relativeURL ,  CancellationToken  token ) 
182+         { 
183+             // Argument check 
184+             PerformStreamCheckAndSeek ( outputStream ) ; 
185+ 
186+             // Get the preferred CDN first and try get the content 
187+             CDNURLProperty  preferredCDN  =  GetPreferredCDN ( ) ; 
188+             bool  isSuccess  =  await  TryGetCDNContent ( preferredCDN ,  downloadClient ,  outputStream ,  relativeURL ,  token ) ; 
189+ 
190+             // If successful, then return 
191+             if  ( isSuccess )  return ; 
192+ 
193+             // If the fail return code occurred by the token, then throw cancellation exception 
194+             token . ThrowIfCancellationRequested ( ) ; 
195+ 
196+             // If not, then continue to get the content from another CDN 
197+             foreach  ( CDNURLProperty  fallbackCDN  in  CDNList . Where ( x =>  ! x . Equals ( preferredCDN ) ) ) 
198+             { 
199+                 isSuccess  =  await  TryGetCDNContent ( fallbackCDN ,  downloadClient ,  outputStream ,  relativeURL ,  token ) ; 
200+ 
201+                 // If successful, then return 
202+                 if  ( isSuccess )  return ; 
203+             } 
204+ 
205+             // If all of them failed, then throw an exception 
206+             if  ( ! isSuccess ) 
207+             { 
208+                 throw  new  AggregateException ( $ "All available CDNs aren't reachable for your network while getting content: { relativeURL } . Please check your internet!") ; 
209+             } 
210+         } 
211+ 
212+         private  static async  ValueTask < bool >  TryGetCDNContent ( CDNURLProperty  cdnProp ,  DownloadClient  downloadClient ,  string  outputPath ,  string  relativeURL ,  int  parallelThread ,  CancellationToken  token ) 
213+         { 
214+             try 
215+             { 
216+                 // Get the URL Status then return boolean and and URLStatus 
217+                 ( bool ,  string )  urlStatus  =  await  TryGetURLStatus ( cdnProp ,  downloadClient ,  relativeURL ,  token ) ; 
218+ 
219+                 // If URL status is false, then return false 
220+                 if  ( ! urlStatus . Item1 )  return  false ; 
221+ 
222+                 // Continue to get the content and return true if successful 
223+                 if  ( ! cdnProp . PartialDownloadSupport ) 
224+                 { 
225+                     // If the CDN marked to not supporting the partial download, then use single thread mode download. 
226+                     using  FileStream  stream  =  File . Create ( outputPath ) ; 
227+                     await  downloadClient . DownloadAsync ( urlStatus . Item2 ,  stream ,  false ,  HttpInstance_DownloadProgressAdapter ,  null ,  null ,  cancelToken :  token ) ; 
228+                     return  true ; 
229+                 } 
230+                 await  downloadClient . DownloadAsync ( urlStatus . Item2 ,  outputPath ,  true ,  progressDelegateAsync :  HttpInstance_DownloadProgressAdapter ,  maxConnectionSessions :  parallelThread ,  cancelToken :  token ) ; 
231+                 return  true ; 
232+             } 
233+             // Handle the error and log it. If fails, then log it and return false 
234+             catch  ( Exception  ex ) 
235+             { 
236+                 LogWriteLine ( $ "Failed while getting CDN content from: { cdnProp . Name }  (prefix: { cdnProp . URLPrefix } ) (relPath: { relativeURL } )\r \n { ex } ",  LogType . Error ,  true ) ; 
237+                 return  false ; 
238+             } 
239+         } 
240+ 
241+         private  static async  ValueTask < bool >  TryGetCDNContent ( CDNURLProperty  cdnProp ,  DownloadClient  downloadClient ,  Stream  outputStream ,  string  relativeURL ,  CancellationToken  token ) 
242+         { 
243+             try 
244+             { 
245+                 // Get the URL Status then return boolean and and URLStatus 
246+                 ( bool ,  string )  urlStatus  =  await  TryGetURLStatus ( cdnProp ,  downloadClient ,  relativeURL ,  token ) ; 
247+ 
248+                 // If URL status is false, then return false 
249+                 if  ( ! urlStatus . Item1 )  return  false ; 
250+ 
251+                 // Continue to get the content and return true if successful 
252+                 await  downloadClient . DownloadAsync ( urlStatus . Item2 ,  outputStream ,  false ,  HttpInstance_DownloadProgressAdapter ,  null ,  null ,  cancelToken :  token ) ; 
253+                 return  true ; 
254+             } 
255+             // Handle the error and log it. If fails, then log it and return false 
256+             catch  ( Exception  ex ) 
257+             { 
258+                 LogWriteLine ( $ "Failed while getting CDN content from: { cdnProp . Name }  (prefix: { cdnProp . URLPrefix } ) (relPath: { relativeURL } )\r \n { ex } ",  LogType . Error ,  true ) ; 
259+                 return  false ; 
260+             } 
261+         } 
262+ 
150263        private  static async  Task < bool >  TryGetCDNContent ( CDNURLProperty  cdnProp ,  Http  httpInstance ,  string  outputPath ,  string  relativeURL ,  int  parallelThread ,  CancellationToken  token ) 
151264        { 
152265            try 
@@ -205,6 +318,27 @@ private static async Task<bool> TryGetCDNContent(CDNURLProperty cdnProp, Http ht
205318            return  ( true ,  absoluteURL ) ; 
206319        } 
207320
321+         private  static async  Task < ( bool ,  string ) >  TryGetURLStatus ( CDNURLProperty  cdnProp ,  DownloadClient  downloadClient ,  string  relativeURL ,  CancellationToken  token ) 
322+         { 
323+             // Concat the URL Prefix and Relative URL 
324+             string  absoluteURL  =  CombineURLFromString ( cdnProp . URLPrefix ,  relativeURL ) ; 
325+ 
326+             LogWriteLine ( $ "Getting CDN Content from: { cdnProp . Name }  at URL: { absoluteURL } ",  LogType . Default ,  true ) ; 
327+ 
328+             // Try check the status of the URL 
329+             ( HttpStatusCode ,  bool )  returnCode  =  await  downloadClient . GetURLStatus ( absoluteURL ,  token ) ; 
330+ 
331+             // If it's not a successful code, then return false 
332+             if  ( ! returnCode . Item2 ) 
333+             { 
334+                 LogWriteLine ( $ "CDN content from: { cdnProp . Name }  (prefix: { cdnProp . URLPrefix } ) (relPath: { relativeURL } ) has returned error code: { returnCode . Item1 }  ({ ( int ) returnCode . Item1 } )",  LogType . Error ,  true ) ; 
335+                 return  ( false ,  absoluteURL ) ; 
336+             } 
337+ 
338+             // Otherwise, return true 
339+             return  ( true ,  absoluteURL ) ; 
340+         } 
341+ 
208342        public  static string  CombineURLFromString ( string  baseURL ,  params  string [ ]  segments ) 
209343        { 
210344            StringBuilder  builder  =  new  StringBuilder ( ) . Append ( baseURL . TrimEnd ( '/' ) ) ; 
@@ -229,5 +363,15 @@ public static string CombineURLFromString(string baseURL, params string[] segmen
229363
230364        // Re-send the events to the static DownloadProgress 
231365        private  static void  HttpInstance_DownloadProgressAdapter ( object  sender ,  DownloadEvent  e )  =>  DownloadProgress ? . Invoke ( sender ,  e ) ; 
366+ 
367+         private  static DownloadEvent  DownloadClientAdapter  =  new  DownloadEvent ( ) ; 
368+ 
369+         private  static void  HttpInstance_DownloadProgressAdapter ( int  read ,  DownloadProgress  downloadProgress ) 
370+         { 
371+             DownloadClientAdapter . SizeToBeDownloaded  =  downloadProgress . BytesTotal ; 
372+             DownloadClientAdapter . SizeDownloaded  =  downloadProgress . BytesDownloaded ; 
373+             DownloadClientAdapter . Read  =  read ; 
374+             DownloadProgress ? . Invoke ( null ,  DownloadClientAdapter ) ; 
375+         } 
232376    } 
233377} 
0 commit comments