示例#1
0
        private void Download(ResourceUrl url, CancellationToken cancellationToken)
        {
            DebugLogger.Log(string.Format("Trying to download from {0}", url));

            long offset = CurrentFileSize();

            DebugLogger.LogVariable(offset, "offset");

            var downloadJobQueue = BuildDownloadJobQueue(url, offset);

            foreach (DownloadJob downloadJob in downloadJobQueue)
            {
                BaseHttpDownloader baseHttpDownloader = new BaseHttpDownloader(downloadJob.Url, _timeout);
                baseHttpDownloader.SetBytesRange(downloadJob.Offset);

                baseHttpDownloader.DataAvailable += (bytes, length) =>
                {
                    bool retry = !_fileStream.Write(bytes, 0, length);

                    if (retry)
                    {
                        throw new DownloaderException("Corrupt data.", DownloaderExceptionStatus.CorruptData);
                    }

                    OnDownloadProgressChanged(CurrentFileSize(), _resource.Size);
                };

                baseHttpDownloader.Download(cancellationToken);
            }

            if (_fileStream.RemainingLength > 0)
            {
                throw new DownloaderException("Data download hasn't been completed.", DownloaderExceptionStatus.Other);
            }
        }
示例#2
0
        private ChunkedFileStream OpenFileStream(CancellationToken cancellationToken)
        {
            var parentDirectory = Path.GetDirectoryName(_destinationFilePath);

            if (!string.IsNullOrEmpty(parentDirectory))
            {
                DirectoryOperations.CreateDirectory(parentDirectory, cancellationToken);
            }

            var chunksRange = CalculateContainingChunksRange(_range);
            int startChunk  = (int)(chunksRange.Start / _chunksData.ChunkSize);
            int endChunk    = (int)_range.End;

            if (_range.End != -1)
            {
                endChunk = (int)(chunksRange.End / _chunksData.ChunkSize);

                if (chunksRange.End % _chunksData.ChunkSize != 0)
                {
                    endChunk += 1;
                }
            }

            _logger.LogTrace(string.Format("Opening chunked file stream for chunks {0}-{1}", startChunk, endChunk));
            return(new ChunkedFileStream(_destinationFilePath, _size, _chunksData,
                                         HashFunction, ChunkedFileStream.WorkFlags.PreservePreviousFile, startChunk, endChunk));
        }
示例#3
0
        public void Download(CancellationToken cancellationToken)
        {
            try
            {
                _logger.LogDebug("Downloading...");
                _logger.LogTrace("size = " + _size);
                for (int i = 0; i < _urls.Length; i++)
                {
                    _logger.LogTrace("urls[" + i + "].Url = " + _urls[i].Url);
                    _logger.LogTrace("urls[" + i + "].Country = " + _urls[i].Country);
                    _logger.LogTrace("urls[" + i + "].PartSize = " + _urls[i].PartSize);
                }

                _logger.LogTrace("chunksData.ChunkSize = " + _chunksData.ChunkSize);
                _logger.LogTrace("chunksData.Chunks.Length = " + _chunksData.Chunks.Length);

                Assert.MethodCalledOnlyOnce(ref _downloadHasBeenCalled, "Download");

                using (var fileStream = OpenFileStream(cancellationToken))
                {
                    bool retry;

                    do
                    {
                        bool success =
                            _urls.Any(url => TryDownload(url, fileStream, cancellationToken));

                        if (success)
                        {
                            retry = false;
                        }
                        else
                        {
                            _logger.LogWarning("All server requests have failed. Checking if retry is possible...");
                            _retryStrategy.OnRequestFailure();
                            _timeoutCalculator.OnRequestFailure();
                            retry = _retryStrategy.ShouldRetry;

                            if (!retry)
                            {
                                throw new DownloadFailureException("Download failure.");
                            }

                            _logger.LogDebug(string.Format("Retry is possible. Waiting {0}ms until before attempt...",
                                                           _retryStrategy.DelayBeforeNextTry));
                            Threading.CancelableSleep(_retryStrategy.DelayBeforeNextTry, cancellationToken);
                            _logger.LogDebug("Trying to download data once again from each server...");
                        }
                    } while (retry);
                }

                _logger.LogDebug("Downloading finished.");
            }
            catch (Exception e)
            {
                _logger.LogDebug("Download has failed.", e);
                throw;
            }
        }
        /// <summary>
        /// Gets a complete changelog of an application.
        /// </summary>
        /// <param name="appSecret">Secret of an application.</param>
        public Changelog[] GetAppChangelog(string appSecret, CancellationToken cancellationToken)
        {
            string path = "/1/apps/{app_secret}/changelog";

            path = path.Replace("{app_secret}", appSecret.ToString());
            string query    = string.Empty;
            var    response = GetResponse(path, query, cancellationToken);

            return(ParseResponse <Changelog[]>(response));
        }
        /// <param name="guid"></param>
        public Job GetJobInfo(string guid, CancellationToken cancellationToken)
        {
            string path = "/v2/jobs/{guid}";

            path = path.Replace("{guid}", guid.ToString());
            string query    = string.Empty;
            var    response = GetResponse(path, query, cancellationToken);

            return(ParseResponse <Job>(response));
        }
        public AppVersionId GetAppLatestAppVersionId(string appSecret, CancellationToken cancellationToken)
        {
            string path = "/1/apps/{app_secret}/versions/latest/id";

            path = path.Replace("{app_secret}", appSecret.ToString());
            string query    = string.Empty;
            var    response = GetResponse(path, query, cancellationToken);

            return(ParseResponse <AppVersionId>(response));
        }
        /// <summary>
        /// Gets detailes app info
        /// </summary>
        /// <param name="appSecret">Secret of an application.</param>
        public App GetApplicationInfo(string appSecret, CancellationToken cancellationToken)
        {
            string path = "/1/apps/{app_secret}";

            path = path.Replace("{app_secret}", appSecret.ToString());
            string query    = string.Empty;
            var    response = GetResponse(path, query, cancellationToken);

            return(ParseResponse <App>(response));
        }
        /// <param name="apiKey">Application owner API key.</param>
        public App[] ListsUserApplications(string apiKey, CancellationToken cancellationToken)
        {
            string        path      = "/1/apps";
            List <string> queryList = new List <string>();

            queryList.Add("api_key=" + apiKey);
            string query    = string.Join("&", queryList.ToArray());
            var    response = GetResponse(path, query, cancellationToken);

            return(ParseResponse <App[]>(response));
        }
        /// <param name="apiKey">Application owner API key. Required when not using a session.</param>
        public Plan GetPlanInfo(string apiKey, CancellationToken cancellationToken)
        {
            string        path      = "/1/me/plan";
            List <string> queryList = new List <string>();

            queryList.Add("api_key=" + apiKey);
            string query    = string.Join("&", queryList.ToArray());
            var    response = GetResponse(path, query, cancellationToken);

            return(ParseResponse <Plan>(response));
        }
        /// <summary>
        /// Gets the basic information for all published versions. When API Key is provided, draft version information is included if draft version exists.
        /// </summary>
        /// <param name="appSecret">Secret of an application.</param>
        /// <param name="apiKey">Application owner API key.</param>
        public AppVersion[] GetAppVersionList(string appSecret, string apiKey, CancellationToken cancellationToken)
        {
            string        path      = "/1/apps/{app_secret}/versions";
            List <string> queryList = new List <string>();

            path = path.Replace("{app_secret}", appSecret.ToString());
            if (apiKey != null)
            {
                queryList.Add("api_key=" + apiKey);
            }
            string query    = string.Join("&", queryList.ToArray());
            var    response = GetResponse(path, query, cancellationToken);

            return(ParseResponse <AppVersion[]>(response));
        }
        /// <summary>
        /// Gets key info. Required providing an app secret. Will find only key that matches given app_secret. This request registers itself as key usage until valid key_secret is providen with this request.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="appSecret"></param>
        /// <param name="keySecret">If provided and valid, will only do a blocked check.</param>
        public LicenseKey GetKeyInfo(string key, string appSecret, string keySecret, CancellationToken cancellationToken)
        {
            string        path      = "/v2/keys/{key}";
            List <string> queryList = new List <string>();

            path = path.Replace("{key}", key.ToString());
            queryList.Add("app_secret=" + appSecret);
            if (keySecret != null)
            {
                queryList.Add("key_secret=" + keySecret);
            }
            string query    = string.Join("&", queryList.ToArray());
            var    response = GetResponse(path, query, cancellationToken);

            return(ParseResponse <LicenseKey>(response));
        }
示例#12
0
        private bool TryDownload(ResourceUrl url, ChunkedFileStream fileStream, CancellationToken cancellationToken)
        {
            try
            {
                _logger.LogDebug(string.Format("Trying to download from {0}", url.Url));
                _logger.LogTrace("fileStream.VerifiedLength = " + fileStream.VerifiedLength);

                var downloadJobQueue = BuildDownloadJobQueue(url, fileStream.VerifiedLength);
                foreach (var downloadJob in downloadJobQueue)
                {
                    _logger.LogDebug(string.Format("Executing download job {0} with offest {1}", downloadJob.Url,
                                                   downloadJob.Range.Start));
                    _logger.LogTrace("fileStream.VerifiedLength = " + fileStream.VerifiedLength);
                    _logger.LogTrace("fileStream.SavedLength = " + fileStream.SavedLength);

                    var baseHttpDownloader = new BaseHttpDownloader(downloadJob.Url, 30000);
                    baseHttpDownloader.SetBytesRange(downloadJob.Range);

                    const long downloadStatusLogInterval = 5000L;
                    var        stopwatch = Stopwatch.StartNew();

                    long downloadedBytes = 0;

                    var job = downloadJob;
                    baseHttpDownloader.DataAvailable += (bytes, length) =>
                    {
                        fileStream.Write(bytes, 0, length);

                        downloadedBytes += length;

                        if (stopwatch.ElapsedMilliseconds > downloadStatusLogInterval)
                        {
                            stopwatch.Reset();
                            stopwatch.Start();

                            _logger.LogDebug(string.Format("Downloaded {0} from {1}", downloadedBytes, job.Url));
                            _logger.LogTrace("fileStream.VerifiedLength = " + fileStream.VerifiedLength);
                            _logger.LogTrace("fileStream.SavedLength = " + fileStream.SavedLength);
                        }

                        OnDownloadProgressChanged(fileStream.VerifiedLength);
                    };

                    baseHttpDownloader.Download(cancellationToken);

                    _logger.LogDebug("Download job execution success.");
                    _logger.LogTrace("fileStream.VerifiedLength = " + fileStream.VerifiedLength);
                    _logger.LogTrace("fileStream.SavedLength = " + fileStream.SavedLength);
                }

                if (fileStream.RemainingLength != 0)
                {
                    throw new IncompleteDataException("Chunks downloading must finish downloading whole file");
                }

                _logger.LogDebug(string.Format("Download from {0} has been successful.", url.Url));
                return(true);
            }
            catch (IncompleteDataException e)
            {
                _logger.LogWarning(string.Format("Unable to download from {0}", url.Url), e);
                return(false);
            }
            catch (InvalidChunkDataException e)
            {
                _logger.LogWarning(string.Format("Unable to download from {0}", url.Url), e);
                return(false);
            }
            catch (DataNotAvailableException e)
            {
                _logger.LogWarning(string.Format("Unable to download from {0}", url.Url), e);
                return(false);
            }
            catch (ServerErrorException e)
            {
                _logger.LogWarning(string.Format("Unable to download from {0}", url.Url), e);
                return(false);
            }
            catch (ConnectionFailureException e)
            {
                _logger.LogWarning(string.Format("Unable to download from {0}", url.Url), e);
                return(false);
            }
        }
        /// <summary>
        /// Retrieves specified resource from API.
        /// </summary>
        /// <param name="path">The path to the resource.</param>
        /// <param name="query">The query of the resource.</param>
        /// <returns>Response with resource result.</returns>
        /// <exception cref="ApiConnectionException">Could not connect to API.</exception>
        public IApiResponse GetResponse(string path, string query, CancellationToken cancellationToken)
        {
            try
            {
                Logger.LogDebug("Getting response for path: '" + path + "' and query: '" + query + "'...");

                var request = new Request
                {
                    Path  = path,
                    Query = query,
                    MainServerExceptions   = new List <Exception>(),
                    CacheServersExceptions = new List <Exception>()
                };

                IApiResponse apiResponse;

                bool retry;

                do
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    if (!TryGetResponse(_connectionSettings.MainServer, request, ServerType.MainServer,
                                        out apiResponse))
                    {
                        if (_connectionSettings.CacheServers != null)
                        {
                            foreach (var cacheServer in _connectionSettings.CacheServers)
                            {
                                if (TryGetResponse(cacheServer, request, ServerType.CacheServer, out apiResponse))
                                {
                                    break;
                                }
                            }
                        }
                    }

                    if (apiResponse == null)
                    {
                        Logger.LogWarning(
                            "Connection attempt to every server has failed. Checking whether retry is possible...");
                        RequestTimeoutCalculator.OnRequestFailure();
                        RequestRetryStrategy.OnRequestFailure();

                        retry = RequestRetryStrategy.ShouldRetry;

                        if (!retry)
                        {
                            Logger.LogError("Retry is not possible.");
                            throw new ApiConnectionException(request.MainServerExceptions,
                                                             request.CacheServersExceptions);
                        }

                        Logger.LogDebug(
                            "Retry is possible. Waiting " + RequestRetryStrategy.DelayBeforeNextTry +
                            "ms before next attempt...");

                        Thread.Sleep(RequestRetryStrategy.DelayBeforeNextTry);

                        Logger.LogDebug("Trying to get response from servers once again...");
                    }
                    else
                    {
                        retry = false;
                    }
                } while (retry);

                Logger.LogDebug("Successfully got response.");
                Logger.LogTrace("Response body: " + apiResponse.Body);

                RequestTimeoutCalculator.OnRequestSuccess();
                RequestRetryStrategy.OnRequestSuccess();

                return(apiResponse);
            }
            catch (Exception e)
            {
                Logger.LogError("Failed to get response.", e);
                throw;
            }
        }
示例#14
0
        public void Download(CancellationToken cancellationToken)
        {
            Assert.MethodCalledOnlyOnce(ref _downloadHasBeenCalled, "Download");

            DebugLogger.Log("Downloading.");

            List <ResourceUrl> validUrls = new List <ResourceUrl>(_resource.ResourceUrls);

            // getting through urls list backwards, because urls may be removed during the process,
            // and it's easier to iterate that way
            validUrls.Reverse();

            int retry = RetriesAmount;

            while (validUrls.Count > 0 && retry > 0)
            {
                for (int i = validUrls.Count - 1; i >= 0 && retry-- > 0; --i)
                {
                    ResourceUrl url = validUrls[i];

                    try
                    {
                        OpenFileStream();

                        Download(url, cancellationToken);

                        CloseFileStream();

                        var validator = new DownloadedResourceValidator();
                        validator.Validate(_destinationFilePath, _resource);

                        return;
                    }
                    catch (WebException e)
                    {
                        // Isn't this catching too much?
                        DebugLogger.LogException(e);

                        // try again
                        break;
                    }
                    catch (DownloaderException downloaderException)
                    {
                        DebugLogger.LogException(downloaderException);
                        switch (downloaderException.Status)
                        {
                        case DownloaderExceptionStatus.EmptyStream:
                            // try another one
                            break;

                        case DownloaderExceptionStatus.CorruptData:
                            // try another one
                            break;

                        case DownloaderExceptionStatus.NotFound:
                            // remove url and try another one
                            validUrls.Remove(url);
                            break;

                        case DownloaderExceptionStatus.Other:
                            // try another one
                            break;

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }
                    finally
                    {
                        CloseFileStream();
                    }
                }

                DebugLogger.Log("Waiting 10 seconds before trying again...");
                Thread.Sleep(10000);
            }

            if (retry <= 0)
            {
                throw new DownloaderException("Too many retries, aborting.", DownloaderExceptionStatus.Other);
            }

            throw new DownloaderException("Cannot download resource.", DownloaderExceptionStatus.Other);
        }
        public void Download(CancellationToken cancellationToken)
        {
            Assert.MethodCalledOnlyOnce(ref _downloadHasBeenCalled, "Download");

            DebugLogger.Log("Downloading.");

            var validUrls = new List<string>(_resource.Urls);
            validUrls.Reverse();

            int retry = RetriesAmount;

            while (validUrls.Count > 0 && retry > 0)
            {
                for (int i = validUrls.Count - 1; i >= 0 && retry-- > 0; --i)
                {
                    string url = validUrls[i];

                    try
                    {
                        OpenFileStream();

                        Download(url, cancellationToken);

                        CloseFileStream();

                        var validator = new DownloadedResourceValidator();
                        validator.Validate(_destinationFilePath, _resource);

                        return;
                    }
                    catch (DownloaderException downloaderException)
                    {
                        DebugLogger.LogException(downloaderException);
                        switch (downloaderException.Status)
                        {
                            case DownloaderExceptionStatus.EmptyStream:
                                // try another one
                                break;
                            case DownloaderExceptionStatus.CorruptData:
                                // try another one
                                break;
                            case DownloaderExceptionStatus.NotFound:
                                // remove url and try another one
                                validUrls.Remove(url);
                                break;
                            case DownloaderExceptionStatus.Other:
                                // try another one
                                break;
                            default:
                                throw new ArgumentOutOfRangeException();
                        }
                    }
                    finally
                    {
                        CloseFileStream();
                    }
                }

                DebugLogger.Log("Waiting 10 seconds before trying again...");
                Thread.Sleep(10000);
            }

            if (retry <= 0)
            {
                throw new DownloaderException("Too many retries, aborting.", DownloaderExceptionStatus.Other);
            }

            throw new DownloaderException("Cannot download resource.", DownloaderExceptionStatus.Other);
        }
        /// <summary>
        /// Gets selected application version diff urls.
        /// </summary>
        /// <param name="appSecret">Secret of an application.</param>
        /// <param name="versionId">Version id.</param>
        /// <param name="country">Country iso code</param>
        /// <param name="keySecret">Key secret provided by key server. This value is optional and is needed only if application is secured by license keys.</param>
        public ResourceUrl[] GetAppVersionDiffUrls(string appSecret, int versionId, string country, string keySecret, CancellationToken cancellationToken)
        {
            string        path      = "/1/apps/{app_secret}/versions/{version_id}/diff_urls";
            List <string> queryList = new List <string>();

            path = path.Replace("{app_secret}", appSecret.ToString());
            path = path.Replace("{version_id}", versionId.ToString());
            if (country != null)
            {
                queryList.Add("country=" + country);
            }
            if (keySecret != null)
            {
                queryList.Add("key_secret=" + keySecret);
            }
            string query    = string.Join("&", queryList.ToArray());
            var    response = GetResponse(path, query, cancellationToken);

            return(ParseResponse <ResourceUrl[]>(response));
        }
        /// <summary>
        /// Gets selected application version diff torrent url.
        /// </summary>
        /// <param name="appSecret">Secret of an application.</param>
        /// <param name="versionId">Version id.</param>
        /// <param name="keySecret">Key secret provided by key server. This value is optional and is needed only if application is secured by license keys.</param>
        public AppDiffTorrentUrl GetAppVersionDiffTorrentUrl(string appSecret, int versionId, string keySecret, CancellationToken cancellationToken)
        {
            string        path      = "/1/apps/{app_secret}/versions/{version_id}/diff_torrent_url";
            List <string> queryList = new List <string>();

            path = path.Replace("{app_secret}", appSecret.ToString());
            path = path.Replace("{version_id}", versionId.ToString());
            if (keySecret != null)
            {
                queryList.Add("key_secret=" + keySecret);
            }
            string query    = string.Join("&", queryList.ToArray());
            var    response = GetResponse(path, query, cancellationToken);

            return(ParseResponse <AppDiffTorrentUrl>(response));
        }
        /// <summary>
        /// Gets selected version diff summary.
        /// </summary>
        /// <param name="appSecret">Secret of an application.</param>
        /// <param name="versionId">Version id.</param>
        public AppDiffSummary GetAppVersionDiffSummary(string appSecret, int versionId, CancellationToken cancellationToken)
        {
            string path = "/1/apps/{app_secret}/versions/{version_id}/diff_summary";

            path = path.Replace("{app_secret}", appSecret.ToString());
            path = path.Replace("{version_id}", versionId.ToString());
            string query    = string.Empty;
            var    response = GetResponse(path, query, cancellationToken);

            return(ParseResponse <AppDiffSummary>(response));
        }