Guest User

Untitled

a guest
Dec 12th, 2023
415
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.62 KB | None | 0 0
  1. using System;
  2. using System.Buffers;
  3. using System.IO;
  4. using System.Net.Http;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7.  
  8. namespace Downloading_Test
  9. {
  10. public class DownloadingCore
  11. {
  12. public delegate void DownloadProgressHandler(long? totalFileSize, long totalBytesDownloaded, double? progressPercentage);
  13.  
  14. public static class HttpClients
  15. {
  16. public static HttpClient General { get; } = new HttpClient();
  17. }
  18.  
  19. private static readonly HttpClient _httpClient = new HttpClient();
  20.  
  21. public static class DownloadWithProgress
  22. {
  23. public static async Task ExecuteAsync(HttpClient httpClient, string downloadPath, string destinationPath, DownloadProgressHandler progress, Func<HttpRequestMessage>? requestMessageBuilder = null, CancellationToken cancellationToken = default)
  24. {
  25. requestMessageBuilder ??= GetDefaultRequestBuilder(downloadPath);
  26. var download = new HttpClientDownloadWithProgress(DownloadingCore.HttpClients.General, destinationPath, requestMessageBuilder);
  27.  
  28. // Use a unique identifier for each download to associate the correct event handler
  29. var downloadId = Guid.NewGuid();
  30.  
  31. // Create a lambda function to capture the correct downloadId
  32. DownloadProgressHandler handler = (totalFileSize, totalBytesDownloaded, progressPercentage) =>
  33. {
  34. progress?.Invoke(totalFileSize, totalBytesDownloaded, progressPercentage);
  35. };
  36.  
  37. download.ProgressChanged += handler;
  38.  
  39. try
  40. {
  41. await download.StartDownload(cancellationToken);
  42. }
  43. catch (Exception ex)
  44. {
  45. Console.WriteLine($"Error during download: {ex.Message}");
  46. }
  47. finally
  48. {
  49. download.ProgressChanged -= handler;
  50. }
  51. }
  52.  
  53. private static Func<HttpRequestMessage> GetDefaultRequestBuilder(string downloadPath)
  54. {
  55. return () => new HttpRequestMessage(HttpMethod.Get, downloadPath);
  56. }
  57. }
  58.  
  59. internal class HttpClientDownloadWithProgress
  60. {
  61. private readonly HttpClient _httpClient;
  62. private readonly string _destinationFilePath;
  63. private readonly Func<HttpRequestMessage> _requestMessageBuilder;
  64. private int _bufferSize = 8192;
  65.  
  66. public event DownloadProgressHandler? ProgressChanged;
  67.  
  68. public HttpClientDownloadWithProgress(HttpClient httpClient, string destinationFilePath, Func<HttpRequestMessage> requestMessageBuilder)
  69. {
  70. _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
  71. _destinationFilePath = destinationFilePath ?? throw new ArgumentNullException(nameof(destinationFilePath));
  72. _requestMessageBuilder = requestMessageBuilder ?? throw new ArgumentNullException(nameof(requestMessageBuilder));
  73. }
  74.  
  75. public async Task StartDownload(CancellationToken cancellationToken = default)
  76. {
  77. var requestMessage = _requestMessageBuilder.Invoke();
  78.  
  79. long? totalFileSize = null; // Calculate or obtain the total file size
  80.  
  81. if (totalFileSize.HasValue && totalFileSize <= 100 * 1024 * 1024)
  82. {
  83. if (requestMessage != null && requestMessage.RequestUri != null)
  84. {
  85. var streamingDownload = new StreamingDownloadWithProgress(_httpClient, _destinationFilePath);
  86. streamingDownload.ProgressChanged += (total, downloaded, progress) => ReportProgress(total, downloaded, progress);
  87. await streamingDownload.StartDownload(requestMessage.RequestUri, cancellationToken);
  88. }
  89. else
  90. {
  91. // Handle the case where requestMessage or its RequestUri is null
  92. // You might want to log a warning or throw an exception
  93. }
  94. }
  95. else
  96. {
  97. HttpResponseMessage response = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
  98. await DownloadAsync(response, cancellationToken);
  99. }
  100. }
  101.  
  102. private async Task DownloadAsync(HttpResponseMessage response, CancellationToken cancellationToken)
  103. {
  104. response.EnsureSuccessStatusCode();
  105.  
  106. var totalBytes = response.Content.Headers.ContentLength;
  107.  
  108. using (var contentStream = await response.Content.ReadAsStreamAsync())
  109. {
  110. await ProcessContentStream(totalBytes, contentStream, cancellationToken);
  111. }
  112. }
  113.  
  114. private async Task ProcessContentStream(long? totalDownloadSize, Stream contentStream, CancellationToken cancellationToken)
  115. {
  116. var totalBytesRead = 0L;
  117. var readCount = 0L;
  118. var buffer = ArrayPool<byte>.Shared.Rent(_bufferSize);
  119. var isMoreToRead = true;
  120.  
  121. try
  122. {
  123. using (var fileStream = new FileStream(_destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.None, _bufferSize, true))
  124. {
  125. do
  126. {
  127. cancellationToken.ThrowIfCancellationRequested();
  128.  
  129. var bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken);
  130. if (bytesRead == 0)
  131. {
  132. isMoreToRead = false;
  133. ReportProgress(totalDownloadSize, totalBytesRead, null); // Pass null for progress as it's not available in this context
  134. continue;
  135. }
  136.  
  137. await fileStream.WriteAsync(buffer, 0, bytesRead, cancellationToken);
  138.  
  139. totalBytesRead += bytesRead;
  140. readCount += 1;
  141.  
  142. if (readCount % 100 == 0)
  143. ReportProgress(totalDownloadSize, totalBytesRead, null);
  144. } while (isMoreToRead);
  145. }
  146. }
  147. finally
  148. {
  149. ArrayPool<byte>.Shared.Return(buffer);
  150. }
  151. }
  152.  
  153. private void ReportProgress(long? totalDownloadSize, long totalBytesRead, double? progress)
  154. {
  155. double? progressPercentage = null;
  156. if (totalDownloadSize.HasValue && totalDownloadSize.Value > 0)
  157. {
  158. progressPercentage = progress ?? Math.Round((double)totalBytesRead / totalDownloadSize.Value * 100, 2);
  159. }
  160.  
  161. ProgressChanged?.Invoke(totalDownloadSize, totalBytesRead, progressPercentage);
  162. }
  163. }
  164.  
  165. // Add the new StreamingDownloadWithProgress class
  166. internal class StreamingDownloadWithProgress
  167. {
  168. private readonly HttpClient _httpClient;
  169. private readonly string _destinationFilePath;
  170. private int _bufferSize = 8192;
  171.  
  172. public event DownloadProgressHandler? ProgressChanged;
  173.  
  174. public StreamingDownloadWithProgress(HttpClient httpClient, string destinationFilePath)
  175. {
  176. _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
  177. _destinationFilePath = destinationFilePath ?? throw new ArgumentNullException(nameof(destinationFilePath));
  178. }
  179.  
  180. public async Task StartDownload(Uri downloadUri, CancellationToken cancellationToken = default)
  181. {
  182. using var response = await _httpClient.GetAsync(downloadUri, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
  183. response.EnsureSuccessStatusCode();
  184.  
  185. var totalBytes = response.Content.Headers.ContentLength;
  186.  
  187. using var contentStream = await response.Content.ReadAsStreamAsync();
  188. await ProcessContentStream(totalBytes, contentStream, cancellationToken);
  189. }
  190.  
  191. private async Task ProcessContentStream(long? totalDownloadSize, Stream contentStream, CancellationToken cancellationToken)
  192. {
  193. var totalBytesRead = 0L;
  194. var readCount = 0L;
  195. var buffer = ArrayPool<byte>.Shared.Rent(_bufferSize);
  196. var isMoreToRead = true;
  197.  
  198. try
  199. {
  200. using var fileStream = new FileStream(_destinationFilePath, FileMode.Create, FileAccess.Write, FileShare.None, _bufferSize, true);
  201.  
  202. do
  203. {
  204. cancellationToken.ThrowIfCancellationRequested();
  205.  
  206. var bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken);
  207. if (bytesRead == 0)
  208. {
  209. isMoreToRead = false;
  210. ReportProgress(totalDownloadSize, totalBytesRead);
  211. continue;
  212. }
  213.  
  214. await fileStream.WriteAsync(buffer, 0, bytesRead, cancellationToken);
  215.  
  216. totalBytesRead += bytesRead;
  217. readCount += 1;
  218.  
  219. if (readCount % 100 == 0)
  220. ReportProgress(totalDownloadSize, totalBytesRead);
  221. } while (isMoreToRead);
  222. }
  223. finally
  224. {
  225. ArrayPool<byte>.Shared.Return(buffer);
  226. }
  227. }
  228.  
  229. private void ReportProgress(long? totalDownloadSize, long totalBytesRead)
  230. {
  231. double? progressPercentage = null;
  232. if (totalDownloadSize.HasValue && totalDownloadSize.Value > 0)
  233. {
  234. progressPercentage = Math.Round((double)totalBytesRead / totalDownloadSize.Value * 100, 2);
  235. }
  236.  
  237. ProgressChanged?.Invoke(totalDownloadSize, totalBytesRead, progressPercentage);
  238. }
  239. }
  240. }
  241. }
Advertisement
Add Comment
Please, Sign In to add comment