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); } }
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)); }
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)); }
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; } }
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)); }