/// <summary> /// Starts downloading an update. /// </summary> /// <param name="buildPath">The local build path.</param> /// <param name="downloadDirectory">The download directory.</param> /// <param name="filesToDownload">A list of files to download.</param> /// <param name="updateMirror">The update mirror to use.</param> public UpdateDownloadResult DownloadUpdates(string buildPath, string downloadDirectory, List <RemoteFileInfo> filesToDownload, UpdateMirror updateMirror) { if (filesToDownload.Count == 0) { return(new UpdateDownloadResult(UpdateDownloadResultType.COMPLETED)); } cancelled = false; this.filesToDownload = filesToDownload; this.downloadDirectory = downloadDirectory; this.updateMirror = updateMirror; foreach (var fileInfo in filesToDownload) { totalUpdateSize += fileInfo.GetDownloadSize(); } verifierWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); verifier = new Verifier(downloadDirectory); verifier.VerificationFailed += Verifier_VerificationFailed; verifier.Completed += Verifier_Completed; webClient = new WebClient() { CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore), Encoding = Encoding.GetEncoding(1252) }; webClient.DownloadProgressChanged += WebClient_DownloadProgressChanged; fileIndexesToDownload = new List <int>(); for (int i = 0; i < filesToDownload.Count; i++) { fileIndexesToDownload.Add(i); } fileIndexesToDownload.Reverse(); fileIndexErrorCounts = new int[filesToDownload.Count]; while (true) { int fileIndex; lock (fileListLocker) { // If we have downloaded all files and the verifier has // succesfully verified them, the list of file indexes to // download has no entries -> we don't have any work left if (fileIndexesToDownload.Count == 0) { break; } fileIndex = fileIndexesToDownload[fileIndexesToDownload.Count - 1]; currentlyDownloadedFile = filesToDownload[fileIndex]; if (fileIndexErrorCounts[fileIndex] > MAX_ERROR_COUNT) { return(CleanUpAndReturnResult(UpdateDownloadResultType.FAILED, "Failed to download file " + currentlyDownloadedFile.FilePath)); } } Task downloadTask = null; try { // By both checking for cancellation and starting a new download // task in the same lock block that's also used in Cancel() we're // making sure that a call to Cancel() will take effect right // away - either we're executing the code above meaning we'll // check for cancellation soon, or we're waiting for a download to // finish - and Cancel() cancels the download operation in case // one is going on lock (cancellationLocker) { if (cancelled) { return(CleanUpAndReturnResult(UpdateDownloadResultType.CANCELLED)); } string fileSavePath = downloadDirectory + currentlyDownloadedFile.GetFilePathWithCompression(); Directory.CreateDirectory(Path.GetDirectoryName(fileSavePath)); downloadTask = webClient.DownloadFileTaskAsync( new Uri(updateMirror.URL + currentlyDownloadedFile.GetFilePathWithCompression().Replace('\\', '/')), fileSavePath); } downloadTask.Wait(); downloadTask.Dispose(); lock (downloadedBytesLocker) downloadedBytes += currentlyDownloadedFile.GetDownloadSize(); verifier.VerifyFile(new IndexedRemoteFileInfo(currentlyDownloadedFile, fileIndex)); } catch (AggregateException ex) { downloadTask.Dispose(); if (cancelled) { return(CleanUpAndReturnResult(UpdateDownloadResultType.CANCELLED)); } UpdaterLogger.Log("Exception while downloading file " + currentlyDownloadedFile.FilePath); LogInnerExceptionRecursive(ex); lock (fileListLocker) { fileIndexErrorCounts[fileIndex]++; } continue; } bool waitingForVerifier = false; lock (fileListLocker) { // Remove the downloaded file from the download queue fileIndexesToDownload.Remove(fileIndex); waitingForVerifier = fileIndexesToDownload.Count == 0; } if (waitingForVerifier) { // We have downloaded all the files, wait for the verifier // to finish verifying them verifier.SetQueueReady(); verifierWaitHandle.WaitOne(); } } return(CleanUpAndReturnResult(UpdateDownloadResultType.COMPLETED)); }
/// <summary> /// Raises an event for download progress. /// </summary> private void WebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) { DownloadProgressEventArgs args = null; lock (downloadedBytesLocker) { args = new DownloadProgressEventArgs(downloadedBytes + e.BytesReceived, totalUpdateSize, e.BytesReceived, currentlyDownloadedFile.GetDownloadSize(), currentlyDownloadedFile.FilePath); } DownloadProgress?.Invoke(this, args); }