示例#1
0
        private void DoResponse()
        {
            try {
                Response = HttpResponseMessage.ReadFrom(Connection.Stream, (p, t) => OnDownloadProgress?.Invoke(this, p, t));
            } catch (Exception ex) {
                Error(ex);
                return;
            }

            if (Response.Connection == HttpConnectionHeader.CLOSE)
            {
                Connection.Dispose();
            }
            if (Response == null)
            {
                Error(new HttpTaskRequestFailedException());
            }

            HttpKeepAliveHeader hkah = Response.Headers.Where(x => x.Name == HttpKeepAliveHeader.NAME).Cast <HttpKeepAliveHeader>().FirstOrDefault();

            if (hkah != null)
            {
                Connection.MaxIdle     = hkah.MaxIdle;
                Connection.MaxRequests = hkah.MaxRequests;
            }

            Connection.Release();
        }
示例#2
0
 public void DownloadBundle(string url, OnAssetBundleLoaded onAssetBundleLoaded, OnDownloadProgress onDownloadProgress)
 {
     //if (coWebReq != null)
     //    StopCoroutine(coWebReq);
     //coWebReq =
     StartCoroutine(RequestBundle(url, 3600f, onAssetBundleLoaded, onDownloadProgress));
 }
 private static void VideoExit(object sender, EventArgs e)
 {
     videoDlProcess.Dispose();
     videoDlProcess = null;
     CheckDownloadFinished();
     OnDownloadProgress?.Invoke();
 }
示例#4
0
 public Updater(AssetService owner)
 {
     m_Owner              = owner;
     m_OnDownloadFailure  = OnDownloadFailure;
     m_OnDownloadSuccess  = OnDownloadSuccess;
     m_OnDownloadProgress = OnDownloadProgress;
 }
示例#5
0
 public void DownloadImage(string url, OnImageLoaded onImageLoaded, OnDownloadProgress onDownloadProgress)
 {
     //if (coWebReq != null)
     //    StopCoroutine(coWebReq);
     //coWebReq =
     StartCoroutine(RequestPicture(url, 60f, onImageLoaded, onDownloadProgress));
 }
示例#6
0
 public void DownloadSave(string url, OnTextLoaded onTextLoaded, OnDownloadProgress onDownloadProgress)
 {
     //if (coWebReq != null)
     //    StopCoroutine(coWebReq);
     //coWebReq =
     StartCoroutine(RequestText(url, 60f, onTextLoaded, onDownloadProgress));
 }
 private static void ChatExit(object sender, EventArgs e)
 {
     ChatDownloadProgress = 100.0f;
     reChatToolProcess.Dispose();
     reChatToolProcess = null;
     CheckDownloadFinished();
     OnDownloadProgress?.Invoke();
 }
示例#8
0
 //*************************************************************
 // Download progress event
 //*************************************************************
 private void Downloader_OnDownloadProgress(object sender, DownloadProgressEventArgs e)
 {
     if (OnDownloadProgress != null)
     {
         foreach (DownloadProgressEventHandler d in OnDownloadProgress.GetInvocationList())
         {
             EventControl.BeginInvoke(d, new object[] { sender, e });
         }
     }
 }
        private static void VideoDataRecieved(object sender, DataReceivedEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(e.Data))
            {
                return;
            }

            string data  = e.Data.Replace(" ", "");
            Regex  r     = new Regex("](.+?)%");
            string match = r.Match(data).Groups[1].Value;

            float.TryParse(match, out float progress);
            VideoDownloadProgress = progress;
            OnDownloadProgress?.Invoke();
        }
示例#10
0
        /// <summary>
        /// Downloads a file
        /// </summary>
        /// <param name="path">Source file's URL</param>
        /// <param name="timeout">Optional timeout.</param>
        /// <returns>File's stream</returns>
        public async Task <ServiceEvent <Stream> > Download(string path, TimeSpan?timeout = null)
        {
            if (string.IsNullOrWhiteSpace(path))
            {
                throw new ArgumentNullException("path");
            }

            Action <long[]> progress = null;

            if (OnDownloadProgress != null)
            {
                progress = p => { OnDownloadProgress.Invoke(this, new DownloadProgressArgs(path, p[0], p[1])); }
            }
            ;
            return(await buildDownloadUrl(path).ExecuteAsync <Stream>(app, timeout: timeout, onProgress: progress));
        }
示例#11
0
        public bool AddDownloadTask(string uri, string localPath, int fileSize, OnDownloadProgress onProgress, OnDownloadError onError, OnDownloadFinished onFinshed, OnDownloadBegin onBegin, OnDownloadValidCheck validChecker, bool logError)
        {
            if (m_IsDownloading)
            {
                Log.e("HttpDownloaderMgr is busy!");
                return(false);
            }

            if (string.IsNullOrEmpty(uri) == true)
            {
                Log.e("uri is empty");
                return(false);
            }

            if (string.IsNullOrEmpty(localPath) == true)
            {
                Log.e("LocalPath is empty");
                return(false);
            }

            if (onError == null || onFinshed == null)
            {
                Log.e("onError & onFinshed should not be null!");
                return(false);
            }

            Clear();

            m_LogError        = logError;
            m_FileSize        = fileSize;
            m_OnProgress      = onProgress;
            m_OnError         = onError;
            m_OnFinished      = onFinshed;
            m_OnDownloadBegin = onBegin;
            m_OnValidCheck    = validChecker;

            m_Uri      = uri;
            m_SaveFile = localPath;

            m_IsDownloading = true;

            m_PreSize        = 0;
            m_LastChangeTime = currentTimeTick;

            StartCoroutine(StartIEnumeratorTask());
            return(true);
        }
示例#12
0
        public async Task <Dictionary <string, byte[]> > DownloadAsync(string link, params string[] fileNames)
        {
            var downloadedFiles = new Dictionary <string, byte[]>();

            using (var webClient = new WebClient {
                BaseAddress = link
            })
            {
                var index = 1;
                foreach (var fileName in fileNames)
                {
                    var content = await webClient.DownloadDataTaskAsync(fileName);

                    downloadedFiles.Add(fileName, content);

                    OnDownloadProgress?.Invoke(this, index++ *100f / fileNames.Length);
                }

                return(downloadedFiles);
            }
        }
示例#13
0
        // 添加下载任务,目前只支持一个任务同时进行
        public bool AddDownloadTask(string uri, string localPath, OnDownloadProgress onProgress, OnDownloadError onError, OnDownloadFinished onFinshed, OnDownloadBegin onBegin = null)
        {
            if (m_IsDownloading)
            {
                Log.e("HttpDownloaderMgr is busy!");
                return(false);
            }

            if (string.IsNullOrEmpty(uri) == true)
            {
                Log.e("uri is empty");
                return(false);
            }

            if (string.IsNullOrEmpty(localPath) == true)
            {
                Log.e("LocalPath is empty");
                return(false);
            }

            if (onError == null || onFinshed == null)
            {
                Log.e("onError & onFinshed should not be null!");
                return(false);
            }

            m_OnProgress      = onProgress;
            m_OnError         = onError;
            m_OnFinished      = onFinshed;
            m_OnDownloadBegin = onBegin;

            m_Uri      = uri;
            m_SaveFile = localPath;

            m_TaskCount++;

            //Log.i("[HttpDownload]about to download new data:" + m_Uri);

            return(true);
        }
示例#14
0
    IEnumerator RequestText(string url, float timeOut, OnTextLoaded onTextLoaded, OnDownloadProgress onDownloadProgress)
    {
        UnityWebRequest webRequest            = UnityWebRequest.Get(url);
        UnityWebRequestAsyncOperation handler = webRequest.SendWebRequest();

        float timeIn    = 0f;
        bool  isAborted = false;

        while (!handler.isDone)
        {
            timeIn += Time.deltaTime;
            if (onDownloadProgress != null)
            {
                onDownloadProgress(handler.progress);
            }
            if (timeIn > timeOut)
            {
                //Security
                isAborted = true;
                webRequest.Abort();
                break;
            }
            yield return(null);
        }

        if (webRequest.isNetworkError || webRequest.isHttpError || isAborted)
        {
            Debug.Log(webRequest.error);
            onTextLoaded(null);
        }
        else
        {
            string textRequested = webRequest.downloadHandler.text;
            onTextLoaded(textRequested);
        }

        yield break;
    }
示例#15
0
        public void Clear()
        {
            if (m_IsDownloading)
            {
                return;
            }

            if (m_WWW != null)
            {
                m_WWW.Dispose();
                m_WWW = null;
            }

            m_PreSize        = 0;
            m_LastChangeTime = currentTimeTick;
            m_Event.Clear();

            m_OnProgress      = null;
            m_OnError         = null;
            m_OnFinished      = null;
            m_OnDownloadBegin = null;
            m_OnValidCheck    = null;
            //StopAllCoroutines();
        }
示例#16
0
    IEnumerator RequestBundle(string url, float timeOut, OnAssetBundleLoaded onAssetBundleLoaded, OnDownloadProgress onDownloadProgress)
    {
        UnityWebRequest webRequest = UnityWebRequest.Get(url);

        webRequest.chunkedTransfer = false;
        webRequest.SetRequestHeader("Accept", "*/*");
        webRequest.SetRequestHeader("Accept-Language", "en-US");
        webRequest.SetRequestHeader("Content-Language", "en-US");
        webRequest.SetRequestHeader("Accept-Encoding", "gzip, deflate");
        webRequest.SetRequestHeader("User-Agent", "runscope/0.1");
        UnityWebRequestAsyncOperation handler = webRequest.SendWebRequest();


        float timeIn    = 0f;
        bool  isAborted = false;

        while (!handler.isDone)
        {
            timeIn += Time.deltaTime;
            if (onDownloadProgress != null)
            {
                onDownloadProgress(handler.progress);
            }
            if (timeIn > timeOut)
            {
                //Security
                isAborted = true;
                webRequest.Abort();
                break;
            }
            yield return(null);
        }

        if (webRequest.isNetworkError || webRequest.isHttpError || isAborted)
        {
            Debug.Log(webRequest.error);
            onAssetBundleLoaded(null);
        }
        else
        {
            AssetBundleCreateRequest bundleRequest = AssetBundle.LoadFromMemoryAsync(webRequest.downloadHandler.data);

            timeIn    = 0f;
            isAborted = false;

            while (!bundleRequest.isDone)
            {
                timeIn += Time.deltaTime;
                if (onDownloadProgress != null)
                {
                    onDownloadProgress(bundleRequest.progress);
                }
                if (timeIn > timeOut)
                {
                    //Security
                    isAborted = true;
                    webRequest.Abort();
                    break;
                }
                yield return(null);
            }

            AssetBundle bundle = bundleRequest.assetBundle;
            if (bundle == null)
            {
                Debug.Log("Bundle error");
            }
            onAssetBundleLoaded(bundle);
        }

        yield break;
    }
示例#17
0
        private void ReadCallBack <T>(Task <int> task, AsyncState <T> requestState)
        {
            task.ContinueWith(t =>
            {
                try
                {
                    requestState.Token.ThrowIfCancellationRequested();

                    var responseStream = requestState.ResponseStream;

                    int read = t.Result;
                    if (read > 0)
                    {
                        requestState.BytesData.Write(requestState.BufferRead, 0, read);

                        var responeStreamTask = responseStream.ReadAsync(requestState.BufferRead, 0, BufferSize);

                        requestState.ResponseBytesRead += read;
                        OnDownloadProgress?.Invoke(requestState.ResponseBytesRead, requestState.ResponseContentLength);

                        ReadCallBack(responeStreamTask, requestState);
                        return;
                    }

                    Interlocked.Increment(ref requestState.Completed);

                    var response = default(T);
                    try
                    {
                        requestState.BytesData.Position = 0;
                        if (typeof(T) == typeof(Stream))
                        {
                            response = (T)(object)requestState.BytesData;
                        }
                        else
                        {
                            var reader = requestState.BytesData;
                            try
                            {
                                if (typeof(T) == typeof(string))
                                {
                                    using (var sr = new StreamReader(reader))
                                    {
                                        response = (T)(object)sr.ReadToEnd();
                                    }
                                }
                                else if (typeof(T) == typeof(byte[]))
                                {
                                    response = (T)(object)reader.ToArray();
                                }
                                else
                                {
                                    response = (T)this.StreamDeserializer(typeof(T), reader);
                                }
                            }
                            finally
                            {
                                if (reader.CanRead)
                                {
                                    reader.Dispose(); // Not yet disposed, but could've been.
                                }
                            }
                        }

                        PclExportClient.Instance.SynchronizeCookies(this);

                        requestState.HandleSuccess(response);
                    }
                    catch (Exception ex)
                    {
                        Log.Debug($"Error Reading Response Error: {ex.Message}", ex);
                        requestState.HandleError(default(T), ex);
                    }
                    finally
                    {
                        PclExportClient.Instance.CloseReadStream(responseStream);

                        CancelAsyncFn = null;
                    }
                }
                catch (Exception ex)
                {
                    HandleResponseError(ex, requestState);
                }
            });
        }
 private static void ChatDataRecieved(object sender, DataReceivedEventArgs e)
 {
     OnDownloadProgress?.Invoke();
 }
示例#19
0
        private async Task <T> SendWebRequestAsync <T>(string httpMethod, string absoluteUrl, object request, CancellationToken token, bool recall = false)
        {
            if (httpMethod == null)
            {
                throw new ArgumentNullException(nameof(httpMethod));
            }

            this.PopulateRequestMetadata(request);

            var requestUri     = absoluteUrl;
            var hasQueryString = request != null && !HttpUtils.HasRequestBody(httpMethod);

            if (hasQueryString)
            {
                var queryString = QueryStringSerializer.SerializeToString(request);
                if (!string.IsNullOrEmpty(queryString))
                {
                    requestUri += "?" + queryString;
                }
            }

            var webReq = this.CreateHttpWebRequest(requestUri);

            if (webReq != null && Proxy != null)
            {
                webReq.Proxy = Proxy;
            }

            var    timedOut = false;
            ITimer timer    = null;

            timer = PclExportClient.Instance.CreateTimer(state =>
            {
                timedOut = true;
                webReq?.Abort();
                webReq = null;
                timer?.Cancel();
                timer = null;
            }, this.Timeout.GetValueOrDefault(DefaultTimeout), this);

            Exception ResolveException(Exception ex)
            {
                if (token.IsCancellationRequested)
                {
                    return(new OperationCanceledException(token));
                }
                if (timedOut)
                {
                    return(PclExportClient.Instance.CreateTimeoutException(ex, "The request timed out"));
                }
                return(ex);
            }

            bool            returningWebResponse = false;
            HttpWebResponse webRes = null;

            T Complete(T response)
            {
                timer.Cancel();
                PclExportClient.Instance.SynchronizeCookies(this);
                ResultsFilterResponse?.Invoke(webRes, response, httpMethod, absoluteUrl, request);
                return(response);
            }

            webReq.Accept = ContentType;

            if (this.EmulateHttpViaPost)
            {
                webReq.Method = "POST";
                webReq.Headers[HttpHeaders.XHttpMethodOverride] = httpMethod;
            }
            else
            {
                webReq.Method = httpMethod;
            }

            PclExportClient.Instance.AddHeader(webReq, Headers);
            PclExport.Instance.Config(webReq, userAgent: UserAgent);

            if (this.authInfo != null && !string.IsNullOrEmpty(this.UserName))
            {
                webReq.AddAuthInfo(this.UserName, this.Password, authInfo);
            }
            else if (this.BearerToken != null)
            {
                webReq.Headers[HttpHeaders.Authorization] = "Bearer " + this.BearerToken;
            }
            else if (this.Credentials != null)
            {
                webReq.Credentials = this.Credentials;
            }
            else if (this.AlwaysSendBasicAuthHeader)
            {
                webReq.AddBasicAuth(this.UserName, this.Password);
            }

            if (!DisableAutoCompression)
            {
                PclExport.Instance.AddCompression(webReq);
            }

            ApplyWebRequestFilters(webReq);

            try
            {
                if (HttpUtils.HasRequestBody(webReq.Method))
                {
                    webReq.ContentType = ContentType;

                    if (RequestCompressionType != null)
                    {
                        webReq.Headers[HttpHeaders.ContentEncoding] = RequestCompressionType;
                    }

                    using var requestStream = await webReq.GetRequestStreamAsync().ConfigAwait();

                    token.ThrowIfCancellationRequested();
                    if (request != null)
                    {
                        StreamSerializer(null, request, requestStream);
                    }
                }
            }
            catch (Exception ex)
            {
                if (Log.IsDebugEnabled)
                {
                    Log.Debug($"Error Sending Request: {ex.Message}", ex);
                }

                throw HandleResponseError <T>(ResolveException(ex), requestUri, request);
            }

            try
            {
                webRes = (HttpWebResponse)await webReq.GetResponseAsync().ConfigAwait();

                {
                    token.ThrowIfCancellationRequested();

                    ApplyWebResponseFilters(webRes);

                    returningWebResponse = typeof(T) == typeof(HttpWebResponse);
                    if (returningWebResponse)
                    {
                        return(Complete((T)(object)webRes));
                    }

                    var responseStream = webRes.ResponseStream();

                    var responseBodyLength = webRes.ContentLength;
                    var bufferRead         = new byte[BufferSize];

                    var totalRead = 0;
                    int read;
                    var ms = MemoryStreamFactory.GetStream();

                    while ((read = await responseStream.ReadAsync(bufferRead, 0, bufferRead.Length, token).ConfigAwait()) != 0)
                    {
                        await ms.WriteAsync(bufferRead, 0, read, token).ConfigAwait();

                        totalRead += read;
                        OnDownloadProgress?.Invoke(totalRead, responseBodyLength);
                    }

                    try
                    {
                        ms.Position = 0;
                        if (typeof(T) == typeof(Stream))
                        {
                            return(Complete((T)(object)ms));
                        }
                        else
                        {
                            var stream = ms;
                            try
                            {
                                if (typeof(T) == typeof(string))
                                {
                                    return(Complete((T)(object)await stream.ReadToEndAsync().ConfigAwait()));
                                }
                                else if (typeof(T) == typeof(byte[]))
                                {
                                    return(Complete((T)(object)stream.ToArray()));
                                }
                                else
                                {
                                    return(Complete((T)this.StreamDeserializer(typeof(T), stream)));
                                }
                            }
                            finally
                            {
                                if (stream.CanRead)
                                {
                                    stream.Dispose(); // Not yet disposed, but could've been.
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        if (Log.IsDebugEnabled)
                        {
                            Log.Debug($"Error Reading Response Error: {ex.Message}", ex);
                        }

                        throw;
                    }
                    finally
                    {
                        responseStream.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                var webEx                 = ex as WebException;
                var firstCall             = !recall;
                var hasRefreshTokenCookie = this.CookieContainer.GetRefreshTokenCookie(BaseUri) != null;
                var hasRefreshToken       = RefreshToken != null || hasRefreshTokenCookie;

                if (firstCall && WebRequestUtils.ShouldAuthenticate(webEx,
                                                                    (!string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password)) ||
                                                                    Credentials != null ||
                                                                    BearerToken != null ||
                                                                    hasRefreshToken ||
                                                                    OnAuthenticationRequired != null))
                {
                    try
                    {
                        if (hasRefreshToken)
                        {
                            var refreshRequest = new GetAccessToken {
                                RefreshToken   = RefreshToken,
                                UseTokenCookie = UseTokenCookie,
                            };
                            var uri = this.RefreshTokenUri ?? this.BaseUri.CombineWith(refreshRequest.ToPostUrl());

                            GetAccessTokenResponse tokenResponse;
                            try
                            {
                                tokenResponse = (await uri.PostJsonToUrlAsync(refreshRequest, requestFilter: req => {
                                    if (UseTokenCookie || hasRefreshTokenCookie)
                                    {
                                        req.CookieContainer = CookieContainer;
                                    }
                                }, token: token).ConfigAwait()).FromJson <GetAccessTokenResponse>();
                            }
                            catch (WebException refreshEx)
                            {
                                var webServiceEx = ServiceClientBase.ToWebServiceException(refreshEx,
                                                                                           stream => StreamDeserializer(typeof(T), stream),
                                                                                           ContentType);

                                if (webServiceEx != null)
                                {
                                    throw new RefreshTokenException(webServiceEx);
                                }

                                throw new RefreshTokenException(refreshEx.Message, refreshEx);
                            }

                            var accessToken   = tokenResponse?.AccessToken;
                            var refreshClient = webReq = (HttpWebRequest)WebRequest.Create(requestUri);
                            var tokenCookie   = this.CookieContainer.GetTokenCookie(BaseUri);

                            if (UseTokenCookie)
                            {
                                if (tokenCookie == null)
                                {
                                    throw new RefreshTokenException("Could not retrieve new AccessToken Cooke from: " + uri);
                                }

                                refreshClient.CookieContainer.SetTokenCookie(BaseUri, tokenCookie);
                            }
                            else
                            {
                                if (string.IsNullOrEmpty(accessToken))
                                {
                                    throw new RefreshTokenException("Could not retrieve new AccessToken from: " + uri);
                                }

                                if (tokenCookie != null)
                                {
                                    this.CookieContainer.SetTokenCookie(accessToken, BaseUri);
                                    refreshClient.CookieContainer.SetTokenCookie(BaseUri, accessToken);
                                }
                                else
                                {
                                    refreshClient.AddBearerToken(this.BearerToken = accessToken);
                                }
                            }

                            return(await SendWebRequestAsync <T>(httpMethod, absoluteUrl, request, token, recall : true).ConfigAwait());
                        }

                        OnAuthenticationRequired?.Invoke();

                        var newReq = (HttpWebRequest)WebRequest.Create(requestUri);

                        if (StoreCookies)
                        {
                            newReq.CookieContainer = CookieContainer;
                        }

                        HandleAuthException(ex, webReq);

                        return(await SendWebRequestAsync <T>(httpMethod, absoluteUrl, request, token, recall : true).ConfigAwait());
                    }
                    catch (WebServiceException)
                    {
                        throw;
                    }
                    catch (Exception /*subEx*/)
                    {
                        throw HandleResponseError <T>(ResolveException(ex), requestUri, request);
                    }
                }

                if (ExceptionFilter != null && webEx?.Response != null)
                {
                    var cachedResponse = ExceptionFilter(webEx, webEx.Response, requestUri, typeof(T));
                    if (cachedResponse is T variable)
                    {
                        return(variable);
                    }
                }

                throw HandleResponseError <T>(ResolveException(ex), requestUri, request);
            }
            finally
            {
                if (!returningWebResponse)
                {
                    webRes?.Dispose();
                }
            }
        }
        /// <summary>
        /// Downloads the specified URL to the destination file stream
        /// </summary>
        /// <param name="destination">The file stream to write content to</param>
        /// <param name="updateFile">The update to download</param>
        /// <param name="startOffset">Offset to resume download at</param>
        /// <param name="cancellationToken">Cancellation token</param>
        public void DownloadToStream(
            Stream destination,
            UpdateFile updateFile,
            long startOffset,
            CancellationToken cancellationToken)
        {
            var progress = new ContentOperationProgress()
            {
                File             = updateFile,
                Current          = startOffset,
                Maximum          = (long)updateFile.Size,
                CurrentOperation = OperationType.DownloadFileProgress
            };

            // Validate starting offset
            if (startOffset >= (long)updateFile.Size)
            {
                throw new Exception($"Start offset {startOffset} cannot be greater than expected file size {updateFile.Size}");
            }

            var url = updateFile.DownloadUrl;

            using (var client = new HttpClient())
            {
                var fileSizeOnServer = GetFileSizeOnServer(client, url, cancellationToken);

                // Make sure our size matches the server's size
                if (fileSizeOnServer != (long)updateFile.Size)
                {
                    throw new Exception($"File size mismatch. Expected {updateFile.Size}, server advertised {fileSizeOnServer}");
                }

                // Build the range request for the download
                using (var updateRequest = new HttpRequestMessage {
                    RequestUri = new Uri(url), Method = HttpMethod.Get
                })
                {
                    updateRequest.Headers.Range = new RangeHeaderValue((long)startOffset, (long)fileSizeOnServer - 1);

                    // Stream the file to disk
                    using (HttpResponseMessage response = client
                                                          .SendAsync(updateRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken)
                                                          .GetAwaiter()
                                                          .GetResult())
                    {
                        if (response.IsSuccessStatusCode)
                        {
                            using (Stream streamToReadFrom = response.Content.ReadAsStreamAsync().GetAwaiter().GetResult())
                            {
                                // Read in chunks while not at the end and cancellation was not requested
                                byte[] readBuffer     = new byte[2097152 * 5];
                                var    readBytesCount = streamToReadFrom.Read(readBuffer, 0, readBuffer.Length);
                                while (!cancellationToken.IsCancellationRequested && readBytesCount > 0)
                                {
                                    destination.Write(readBuffer, 0, readBytesCount);

                                    progress.Current += readBytesCount;
                                    OnDownloadProgress?.Invoke(this, progress);

                                    readBytesCount = streamToReadFrom.Read(readBuffer, 0, readBuffer.Length);
                                }
                            }
                        }
                        else
                        {
                            throw new Exception($"Failed to get content of update from {url}: {response.ReasonPhrase}");
                        }
                    }
                }
            }
        }