csharp/Accelerider/Accelerider.Windows/Source/Accelerider.Windows.TransferService/Download/PrimitiveMethods.Download.cs

PrimitiveMethods.Download.cs
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using Accelerider.Windows.Infrastructure;

namespace Accelerider.Windows.TransferService
{
    public static clast DownloadPrimitiveMethods
    {
        public static HttpWebRequest ToRequest(this string remotePath)
        {
            return WebRequest.CreateHttp(remotePath);
        }

        public static HttpWebRequest Slice(this HttpWebRequest request, (long offset, long length) block)
        {
            request.AddRangeBasedOffsetLength(block.offset, block.length);
            return request;
        }

        public static async Task GetResponseAsync(HttpWebRequest request)
        {
            return (HttpWebResponse)await request.GetResponseAsync();
        }

        public static FileStream ToStream(this string localPath)
        {
            return new FileStream(localPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write, 1024 * 1024);
        }

        public static FileStream Slice(this FileStream stream, (long offset, long length) block)
        {
            stream.Position = block.offset;
            return stream;
        }

        public static IObservable CreateBlockDownloadItem(
            Func streamPairFactory,
            BlockTransferContext context) => Observable.Create(o =>
        {
            var cancellationTokenSource = new CancellationTokenSource();
            var cancellationToken = cancellationTokenSource.Token;

            // Execute copy stream by async.
            Task.Run(async () =>
            {
                try
                {
                    (HttpWebResponse response, Stream outputStream) = await streamPairFactory();

                    using (response)
                    using (var inputStream = response.GetResponseStream())
                    using (outputStream)
                    {
                        byte[] buffer = new byte[128 * 1024];
                        int count;

                        Guards.ThrowIfNull(inputStream);

                        // ReSharper disable once PossibleNullReferenceException
                        while ((count = inputStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            if (cancellationToken.IsCancellationRequested)
                            {
                                Debug.WriteLine($"[CANCELLED] [{DateTime.Now}] BLOCK DOWNLOAD ITEM ({context.Offset})");
                                o.OnError(new BlockTransferException(context, new OperationCanceledException()));
                                return;
                            }

                            outputStream.Write(buffer, 0, count);
                            o.OnNext((context.Offset, count));
                        }
                    }

                    o.OnCompleted();
                }
                catch (Exception e)
                {
                    o.OnError(new BlockTransferException(context, e));
                }
            }, cancellationToken);

            return () =>
            {
                Debug.WriteLine($"[DISPOSED] [{DateTime.Now}] BLOCK DOWNLOAD ITEM ({context.Offset})");
                cancellationTokenSource.Cancel();
            };
        });
    }
}