src/Microsoft.PackageManagement.NuGetProvider/NugetLightClient.cs
/// <summary>
/// Download data from remote via uri query.
/// </summary>
/// <param name="fileName">A file to store the downloaded data.</param>
/// <param name="query">Uri query</param>
/// <param name="request">An object passed in from the PackageManagement platform that contains APIs that can be used to interact with it </param>   
/// <param name="networkCredential">Credential to pass along to get httpclient</param>
/// <param name="progressTracker">Utility class to help track progress</param>
/// <returns></returns>
Download data from remote via uri query.
Download data from remote via uri query .
internal static async Task<long> DownloadDataToFileAsync(string fileName, string query, NuGetRequest request,
            NetworkCredential networkCredential, ProgressTracker progressTracker)
        {
            request.Verbose(Messages.DownloadingPackage, query);
            var httpClient = request.Client;
            int remainingTry = 3;
            long totalDownloaded = 0;
            long totalBytesToReceive = 0;
            bool cleanUp = false;
            CancellationTokenSource cts = new CancellationTokenSource(); ;
            Stream input = null;
            Timer timer = null;
            FileStream output = null;
            object lockObject = new object();
            Action cleanUpAction = () => {
                lock (lockObject)
                {
                    if (!cleanUp)
                    {
                        try
                        {
                            if (timer != null)
                            {
                                timer.Change(Timeout.Infinite, Timeout.Infinite);
                                timer.Dispose();
                            }
                            if (cts != null)
                            {
                                cts.Cancel();
                                cts.Dispose();
                            }
                        }
                        catch { }
                        try
                        {
                            if (input != null)
                            {
                                input.Dispose();
                            }
                            if (output != null)
                            {
                                output.Dispose();
                            }
                            if (totalBytesToReceive != totalDownloaded)
                            {
                                request.Verbose(string.Format(Resources.Messages.IncompleteDownload, totalDownloaded, totalBytesToReceive));
                            }
                            if (totalDownloaded == 0 && File.Exists(fileName))
                            {
                                File.Delete(fileName);
                            }
                        }
                        catch { }
                        cleanUp = true;
                    }
                }
            };
            while (remainingTry > 0)
            {
                if (request.IsCanceled)
                {
                    break;
                }
                input = null;
                output = null;
                totalDownloaded = 0;
                try
                {
                    remainingTry -= 1;
                    lock (lockObject)
                    {
                        timer = new Timer(_ =>
                        {
                            if (request.IsCanceled)
                            {
                                cleanUpAction();
                            }
                        }, null, 500, 1000);
                        cts = new CancellationTokenSource();
                        cleanUp = false;
                    }
                    var response = await httpClient.GetAsync(query, HttpCompletionOption.ResponseHeadersRead, cts.Token);
                    if (response.Content != null && response.Content.Headers != null)
                    {
                        totalBytesToReceive = response.Content.Headers.ContentLength ?? 0;
                        double totalBytesToReceiveMB = (totalBytesToReceive / 1024f) / 1024f;
                        input = await response.Content.ReadAsStreamAsync();
                        byte[] bytes = new byte[1024 * 64];
                        output = File.Open(fileName, FileMode.OpenOrCreate);
                        int current = 0;
                        double lastPercent = 0;
                        current = await input.ReadAsync(bytes, 0, bytes.Length, cts.Token);
                        request.Progress(progressTracker.ProgressID, progressTracker.StartPercent,
                            string.Format(CultureInfo.CurrentCulture, Resources.Messages.DownloadingProgress, 0, (totalBytesToReceive / 1024f) / 1024f));
                        while (current > 0)
                        {
                            totalDownloaded += current;
                            await output.WriteAsync(bytes, 0, current, cts.Token);
                            double percent = totalDownloaded * 1.0 / totalBytesToReceive;
                            if (percent > lastPercent + 0.1)
                            {
                                lastPercent = percent;
                                var progressPercent = progressTracker.ConvertPercentToProgress(percent);
                                request.Progress(progressTracker.ProgressID, (int)progressPercent,
                                    string.Format(CultureInfo.CurrentCulture, Resources.Messages.DownloadingProgress, (totalDownloaded / 1024f) / 1024f, totalBytesToReceiveMB));
                            }
                            current = await input.ReadAsync(bytes, 0, bytes.Length, cts.Token);
                        }
                        if (totalDownloaded == totalBytesToReceive)
                        {
                            request.Progress(progressTracker.ProgressID, progressTracker.EndPercent,
                                string.Format(CultureInfo.CurrentCulture, Resources.Messages.DownloadingProgress, totalDownloaded, totalBytesToReceive));
                            request.Verbose(Messages.CompletedDownload, query);
                            break;
                        }
                    }
                    if (request.IsCanceled)
                    {
                        break;
                    }
                    request.Verbose(Resources.Messages.RetryingDownload, query, remainingTry);
                }
                catch (Exception ex)
                {
                    request.Verbose(ex.Message);
                    request.Debug(ex.StackTrace);
                    request.Verbose(Resources.Messages.RetryingDownload, query, remainingTry);
                }
                finally
                {
                    cleanUpAction();
                }
            }
            return totalDownloaded;
        }
internal static async Task < long > DownloadDataToFileAsync ( string fileName , string query , NuGetRequest request , NetworkCredential networkCredential , ProgressTracker progressTracker ) { request . Verbose ( Messages . DownloadingPackage , query ) ; var httpClient = request . Client ; int remainingTry = 3 ; long totalDownloaded = 0 ; long totalBytesToReceive = 0 ; bool cleanUp = false ; CancellationTokenSource cts = new CancellationTokenSource ( ) ; ; Stream input = null ; Timer timer = null ; FileStream output = null ; object lockObject = new object ( ) ; Action cleanUpAction = ( ) => { lock ( lockObject ) { if ( ! cleanUp ) { try { if ( timer != null ) { timer . Change ( Timeout . Infinite , Timeout . Infinite ) ; timer . Dispose ( ) ; } if ( cts != null ) { cts . Cancel ( ) ; cts . Dispose ( ) ; } } catch { } try { if ( input != null ) { input . Dispose ( ) ; } if ( output != null ) { output . Dispose ( ) ; } if ( totalBytesToReceive != totalDownloaded ) { request . Verbose ( string . Format ( Resources . Messages . IncompleteDownload , totalDownloaded , totalBytesToReceive ) ) ; } if ( totalDownloaded == 0 && File . Exists ( fileName ) ) { File . Delete ( fileName ) ; } } catch { } cleanUp = true ; } } } ; while ( remainingTry > 0 ) { if ( request . IsCanceled ) { break ; } input = null ; output = null ; totalDownloaded = 0 ; try { remainingTry -= 1 ; lock ( lockObject ) { timer = new Timer ( _ => { if ( request . IsCanceled ) { cleanUpAction ( ) ; } } , null , 500 , 1000 ) ; cts = new CancellationTokenSource ( ) ; cleanUp = false ; } var response = await httpClient . GetAsync ( query , HttpCompletionOption . ResponseHeadersRead , cts . Token ) ; if ( response . Content != null && response . Content . Headers != null ) { totalBytesToReceive = response . Content . Headers . ContentLength ?? 0 ; double totalBytesToReceiveMB = ( totalBytesToReceive / 1024f ) / 1024f ; input = await response . Content . ReadAsStreamAsync ( ) ; byte [ ] bytes = new byte [ 1024 * 64 ] ; output = File . Open ( fileName , FileMode . OpenOrCreate ) ; int current = 0 ; double lastPercent = 0 ; current = await input . ReadAsync ( bytes , 0 , bytes . Length , cts . Token ) ; request . Progress ( progressTracker . ProgressID , progressTracker . StartPercent , string . Format ( CultureInfo . CurrentCulture , Resources . Messages . DownloadingProgress , 0 , ( totalBytesToReceive / 1024f ) / 1024f ) ) ; while ( current > 0 ) { totalDownloaded += current ; await output . WriteAsync ( bytes , 0 , current , cts . Token ) ; double percent = totalDownloaded * 1.0 / totalBytesToReceive ; if ( percent > lastPercent + 0.1 ) { lastPercent = percent ; var progressPercent = progressTracker . ConvertPercentToProgress ( percent ) ; request . Progress ( progressTracker . ProgressID , ( int ) progressPercent , string . Format ( CultureInfo . CurrentCulture , Resources . Messages . DownloadingProgress , ( totalDownloaded / 1024f ) / 1024f , totalBytesToReceiveMB ) ) ; } current = await input . ReadAsync ( bytes , 0 , bytes . Length , cts . Token ) ; } if ( totalDownloaded == totalBytesToReceive ) { request . Progress ( progressTracker . ProgressID , progressTracker . EndPercent , string . Format ( CultureInfo . CurrentCulture , Resources . Messages . DownloadingProgress , totalDownloaded , totalBytesToReceive ) ) ; request . Verbose ( Messages . CompletedDownload , query ) ; break ; } } if ( request . IsCanceled ) { break ; } request . Verbose ( Resources . Messages . RetryingDownload , query , remainingTry ) ; } catch ( Exception ex ) { request . Verbose ( ex . Message ) ; request . Debug ( ex . StackTrace ) ; request . Verbose ( Resources . Messages . RetryingDownload , query , remainingTry ) ; } finally { cleanUpAction ( ) ; } } return totalDownloaded ; }
Download data from remote via uri query.
Download data from remote via uri query .
// try downloading for 3 times // function to perform cleanup // if clean up is done before, don't need to do again // dispose timer // dispose cts token // dispose input and output stream // it is important that we dispose of the output here, otherwise we may not be able to delete the file // if the download didn't complete, log verbose message // if we couldn't download anything // if user cancel the request, no need to do anything // decrease try by 1 // create new timer and cancellation token source // check every second to see whether request is cancelled // the total amount of bytes we need to download in megabytes // Read response asynchronously and write out a file // The return value is for the caller to wait for the async operation to complete. // buffer size of 64 KB, this seems to be preferable buffer size, not too small and not too big // here we read content that we got from the http response stream into the bytes array // report initial progress // here we write the bytes array content into the file // don't want to report too often (slow down performance) // percent between startProgress and endProgress // report the progress // here we read content that we got from the http response stream into the bytes array // check that we download everything // report that we finished with the download // otherwise, we have to retry again // if request is canceled, don't retry // if there is exception, we will retry too
None
fileName
string
A file to store the downloaded data.
A file to store the downloaded data .
query
string
None
request
NuGetRequest
An object passed in from the PackageManagement platform that contains APIs that can be used to interact with it
An object passed in from the PackageManagement platform that contains APIs that can be used to interact with it
networkCredential
NetworkCredential
Credential to pass along to get httpclient
Credential to pass along to get httpclient
progressTracker
ProgressTracker
Utility class to help track progress
Utility class to help track progress