public async Task <bool> GetPartialSessionStream(SegmentDownloadProperties j) { Stream stream; try { string partialOutput = string.Format("{0}.{1:000}", downloadPartialOutputPath, j.PartRange + 1); FileInfo fileinfo = new FileInfo(partialOutput); #if DEBUG Console.WriteLine($"\tPart {j.PartRange + 1} > Start: {j.StartRange}{(j.StartRange == 0 ? "\t" : "")}\tEnd: {j.EndRange}\tSize: {BpUtility.ToBytesCount(j.EndRange - j.StartRange)}"); #endif long existingLength = fileinfo.Exists ? fileinfo.Length : 0; long fileSize = (j.EndRange - j.StartRange) + 1; if (existingLength > fileSize) { fileinfo.Create(); } if (existingLength != fileSize) { using (HttpClient client = new HttpClient()) { HttpRequestMessage request = new HttpRequestMessage() { RequestUri = new Uri(downloadPartialInputPath) }; request.Headers.TryAddWithoutValidation("User-Agent", App.UserAgent); request.Headers.Range = new RangeHeaderValue(j.StartRange + existingLength, j.EndRange); HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, downloadPartialToken); using (stream = fileinfo.Open(FileMode.Append, FileAccess.Write)) { try { await ReadPartialRemoteStream(response, stream, existingLength, j.PartRange, j.EndRange - j.StartRange); } catch (OperationCanceledException) { stream.Dispose(); throw new OperationCanceledException(); } } } } else if (existingLength == fileSize) { segmentDownloadProperties[j.PartRange] = new SegmentDownloadProperties(fileSize, 0, fileSize, new TimeSpan().TotalSeconds) { CurrentReceived = 0 }; } } catch (OperationCanceledException) { #if DEBUG Console.WriteLine($"Download cancelled for part {j.PartRange + 1}"); #endif return(true); } catch (Exception ex) { #if DEBUG Console.WriteLine($"{ex}"); #endif return(false); } return(true); }
public void DownloadFileMultipleSession(string input, string output, string customMessage = "", int threads = 1, CancellationToken token = new CancellationToken()) { downloadThread = threads; downloadPartialToken = token; downloadPartialInputPath = input; downloadPartialOutputPath = output; OnCompleted(new DownloadProgressCompleted() { DownloadCompleted = false }); downloadPartialSize = GetContentLength(downloadPartialInputPath) ?? 0; long startContent, endContent; segmentDownloadTask = new List <Task>(); segmentDownloadProperties = new List <SegmentDownloadProperties>(); List <ChunkRanges> chunkRanges = new List <ChunkRanges>(); long partitionSize = (long)Math.Ceiling((double)downloadPartialSize / downloadThread); for (int i = 0; i < downloadThread; i++) { startContent = i * (downloadPartialSize / downloadThread); endContent = i + 1 == downloadThread ? downloadPartialSize : ((i + 1) * (downloadPartialSize / downloadThread)) - 1; segmentDownloadProperties.Add(new SegmentDownloadProperties(0, 0, 0, 0) { CurrentReceived = 0, StartRange = startContent, EndRange = endContent, PartRange = i }); } OnResumabilityChanged(new DownloadStatusChanged(true)); #if DEBUG Console.WriteLine($"\r\nStarting Partial Download!\r\n\tTotal Size: {BpUtility.ToBytesCount(downloadPartialSize)} ({downloadPartialSize} bytes)\r\n\tThreads/Chunks: {downloadThread}"); #endif Status = ParallelHttpClientStatus.Downloading; try { foreach (SegmentDownloadProperties j in segmentDownloadProperties) { segmentDownloadTask.Add(Task.Run(async() => { while (!await GetPartialSessionStream(j)) { #if DEBUG Console.WriteLine($"Retrying to connect for chunk no: {j.PartRange + 1}..."); #endif Thread.Sleep(1000); } }, downloadPartialToken)); } Task.Run(() => GetPartialDownloadEvents()); Task.WhenAll(segmentDownloadTask).GetAwaiter().GetResult(); } catch (Exception ex) { #if DEBUG Console.WriteLine($"{ex}"); #endif } if (!downloadPartialToken.IsCancellationRequested) { try { MergePartialChunks(); } catch (OperationCanceledException ex) { #if DEBUG Console.WriteLine("Merging cancelled!"); #endif throw new OperationCanceledException("", ex); } } else { segmentDownloadTask.Clear(); #if DEBUG Console.WriteLine("Download cancelled!"); #endif throw new OperationCanceledException(); } segmentDownloadTask.Clear(); #if DEBUG Console.WriteLine(" Done!"); #endif Status = ParallelHttpClientStatus.Idle; }