winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

HttpClientHelper.cs (4847B)


      1 // -----------------------------------------------------------------------------
      2 // <copyright file="HttpClientHelper.cs" company="Microsoft Corporation">
      3 //     Copyright (c) Microsoft Corporation. Licensed under the MIT License.
      4 // </copyright>
      5 // -----------------------------------------------------------------------------
      6 
      7 namespace Microsoft.WinGet.Client.Engine.Helpers
      8 {
      9     using System;
     10     using System.Diagnostics;
     11     using System.IO;
     12     using System.Management.Automation;
     13     using System.Net.Http;
     14     using System.Threading.Tasks;
     15     using Microsoft.WinGet.Client.Engine.Common;
     16     using Microsoft.WinGet.Common.Command;
     17     using Microsoft.WinGet.Resources;
     18 
     19     /// <summary>
     20     /// Helper class for HttpClient calls.
     21     /// </summary>
     22     internal class HttpClientHelper
     23     {
     24         /// <summary>
     25         /// The user agent of this module.
     26         /// </summary>
     27         public const string UserAgent = "winget-powershell";
     28 
     29         private static readonly HttpClient Client;
     30 
     31         static HttpClientHelper()
     32         {
     33             Client = new HttpClient();
     34         }
     35 
     36         /// <summary>
     37         /// Downloads a file from a url.
     38         /// </summary>
     39         /// <param name="url">Url.</param>
     40         /// <param name="fileName">File name.</param>
     41         /// /// <param name="pwshCmdlet">PowershellCmdlet.</param>
     42         /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
     43         public async Task DownloadUrlWithProgressAsync(string url, string fileName, PowerShellCmdlet pwshCmdlet)
     44         {
     45             pwshCmdlet.Write(StreamType.Verbose, $"Downloading {url}");
     46             using var request = new HttpRequestMessage(HttpMethod.Get, url);
     47             request.Headers.Add("User-Agent", UserAgent);
     48 
     49             var cancellationToken = pwshCmdlet.GetCancellationToken();
     50             using var response = await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
     51             response.EnsureSuccessStatusCode();
     52 
     53             try
     54             {
     55                 long? contentLength = response.Content.Headers.ContentLength;
     56                 var responseStream = await response.Content.ReadAsStreamAsync();
     57 
     58                 using var fileStream = File.Open(fileName, FileMode.OpenOrCreate);
     59 
     60                 if (contentLength.HasValue)
     61                 {
     62                     pwshCmdlet.Write(StreamType.Verbose, $"Size {contentLength} bytes");
     63 
     64                     byte[] buffer = new byte[Constants.OneMB];
     65                     int bytesRead, totalBytes = 0;
     66 
     67                     var activityId = pwshCmdlet.GetNewProgressActivityId();
     68                     double lengthInMB = (double)contentLength.Value / Constants.OneMB;
     69                     try
     70                     {
     71                         int maxPercentComplete = 0;
     72                         while ((bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
     73                         {
     74                             await fileStream.WriteAsync(buffer, 0, bytesRead, cancellationToken);
     75                             totalBytes += bytesRead;
     76 
     77                             int percentComplete = (int)((double)totalBytes / contentLength * 100);
     78                             if (percentComplete > maxPercentComplete)
     79                             {
     80                                 maxPercentComplete = percentComplete;
     81                                 ProgressRecord record = new (activityId, url, Resources.DownloadingMessage)
     82                                 {
     83                                     RecordType = ProgressRecordType.Processing,
     84                                 };
     85 
     86                                 double progress = (double)totalBytes / Constants.OneMB;
     87                                 record.StatusDescription = $"{progress:0.0} MB / {lengthInMB:0.0} MB";
     88                                 record.PercentComplete = percentComplete;
     89                                 pwshCmdlet.Write(StreamType.Progress, record);
     90                             }
     91                         }
     92                     }
     93                     finally
     94                     {
     95                         pwshCmdlet.CompleteProgress(activityId, url, Resources.DownloadingMessage, true);
     96                     }
     97                 }
     98                 else
     99                 {
    100                     pwshCmdlet.Write(StreamType.Verbose, $"Content-Length not found in response");
    101                     await responseStream.CopyToAsync(fileStream);
    102                 }
    103             }
    104             catch (Exception)
    105             {
    106                 if (File.Exists(fileName))
    107                 {
    108                     File.Delete(fileName);
    109                 }
    110 
    111                 throw;
    112             }
    113         }
    114     }
    115 }