/// <summary> /// Get properties of file asynchronously. /// </summary> /// <returns> /// FileProperties in asynchronous task. /// </returns> /// <param name="uri">URI of file.</param> private static async Task <FileProperties> GetFilePropertiesAsync(string uri) { try { using (var request = new HttpRequestMessage(HttpMethod.Get, uri)) { request.SetTimeout(TimeSpan.FromSeconds(Singleton.Settings.TimeoutSeconds)); request.Headers.Range = new RangeHeaderValue(from: 0, to: 0); request.Headers.Add("User-Agent", Path.GetFileNameWithoutExtension(AppDomain.CurrentDomain.FriendlyName)); string[] s = new Uri(uri).UserInfo.Split(':'); if (s != null && s.Length == 2) { Console.WriteLine($"{uri}: Authenticating with Basic authentication..."); BasicAuthentication(request, s); } using (var response = await HttpClient.SendAsync(request)) { response.EnsureSuccessStatusCode(); FileProperties properties = new FileProperties(); if (response.Content.Headers.ContentDisposition == null) { if (response.Content.Headers.TryGetValues("Content-Disposition", out IEnumerable <string> contentDisposition)) { response.Content.Headers.ContentDisposition = ContentDispositionHeaderValue.Parse(contentDisposition.ToArray()[0].TrimEnd(';').Replace("\"", "")); } } properties.Name = response.Content.Headers?.ContentDisposition?.FileName ?? response.RequestMessage.RequestUri.Segments.LastOrDefault(); if (response.Content.Headers.TryGetValues(@"Content-Range", out IEnumerable <string> range)) { properties.Size = long.Parse(System.Text.RegularExpressions.Regex.Match(range.Single(), @"(?<=^bytes\s[0-9]+\-[0-9]+/)[0-9]+$").Value); } else { properties.Size = 0; } properties.RangeAccepted = response.Headers.AcceptRanges.Contains("bytes"); properties.ContentStream = await response.Content.ReadAsStreamAsync(); return(properties); } } } catch (Exception e) { throw e; } }
/// <summary> /// Prepare file for download asynchronously. /// </summary> /// <returns> /// Boolean of whether preparation is successful in asynchronous task. /// </returns> /// <param name="uri">URI of file.</param> public async Task <bool> LoadFileAsync(string uri) { try { int retry = Singleton.Settings.TimeoutRetries; FileProperties properties = null; while (retry >= 0 && properties == null) { await Task.Delay(TimeSpan.FromSeconds((Singleton.Settings.TimeoutRetries - retry) * Singleton.Settings.LinearBackoffInterval)); try { properties = await GetFilePropertiesAsync(uri); } catch (TimeoutException te) { retry--; Console.WriteLine($"{uri}: {te.GetType().FullName}: {te.Message}"); } catch (Exception e) { Console.WriteLine($"{uri}: {e.GetType().FullName}: {e.Message}"); return(false); } } _filePath = $"{Singleton.Settings.DownloadLocation}/{properties.Name}"; if (properties == null) { return(false); } else if (properties.Name == "/") { Console.WriteLine($"{uri}: URI is not a file"); return(false); } else if (properties.Size == 0) { return(true); } // Uncomment to debug properties //var dump = ObjectDumper.Dump(properties); //Console.WriteLine(dump); if (!properties.RangeAccepted) { Console.WriteLine($"{uri}: Segmented downloading not supported, continuing with normal download..."); } int count = 0; foreach (var(start, end) in SegmentPosition(properties.Size, properties.RangeAccepted ? Singleton.Settings.SegmentsPerFile : 1)) { retry = Singleton.Settings.TimeoutRetries; count++; bool isSuccessStatusCode = false; while (retry >= 0 && !isSuccessStatusCode) { await Task.Delay(TimeSpan.FromSeconds((Singleton.Settings.TimeoutRetries - retry) * Singleton.Settings.LinearBackoffInterval)); Console.WriteLine($"{uri}: Building segment {count}..."); try { using (var request = new HttpRequestMessage(HttpMethod.Get, uri)) { string[] s = new Uri(uri).UserInfo.Split(':'); if (s != null && s.Length == 2) { Console.WriteLine($"{uri}: Authenticating with Basic authentication..."); BasicAuthentication(request, s); } request.SetTimeout(TimeSpan.FromSeconds(Singleton.Settings.TimeoutSeconds)); request.Headers.Range = new RangeHeaderValue(start, end); request.Headers.Add("User-Agent", Path.GetFileNameWithoutExtension(AppDomain.CurrentDomain.FriendlyName)); var responseMessage = await HttpClient.SendAsync(request); isSuccessStatusCode = responseMessage.IsSuccessStatusCode; responseMessage.EnsureSuccessStatusCode(); _fileSegments.Add(new FileSegment { ID = count, Start = start, End = end, BytesRead = 0, Content = await responseMessage.Content.ReadAsStreamAsync() }); } } catch (TimeoutException te) { retry--; Console.WriteLine($"{uri}: {te.GetType().FullName}: {te.Message}"); } catch (Exception e) { Console.WriteLine($"{uri}: {e.GetType().FullName}: {e.Message}"); } } } // Uncomment to debug fileSegments //dump = ObjectDumper.Dump(fileSegments); //Console.WriteLine(dump); } catch (Exception e) { Console.WriteLine($"{uri}: {e.GetType().FullName}: {e.Message}"); return(false); } return(true); }