diff --git a/CHANGELOG.md b/CHANGELOG.md index d6ec0c2..87041ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Atlassian Downloader - Changelog ## 2.x +* `2.0.0.2` - - minor update: + * Added `maxRetries (default: 5)` and `delayBetweenRetries (default: 2500, milliseconds)` args, to redownload file if connection will be reset. + * Updated dependencies. * `2.0.0.1` - - minor update: * Fix default output dir, enable nullables, fix compiler warnings #43 * Remove redundant parameters from publish profiles #42 diff --git a/src/Core/DownloaderService.cs b/src/Core/DownloaderService.cs index 81b9bf5..413c5ce 100644 --- a/src/Core/DownloaderService.cs +++ b/src/Core/DownloaderService.cs @@ -213,31 +213,43 @@ internal class DownloaderService : IHostedService private async Task DownloadFile(ResponseItem file, string outputFile, CancellationToken cancellationToken) { - if (!string.IsNullOrEmpty(file.Md5)) + for (int attempt = 1; attempt <= options.MaxRetries; attempt++) { - File.WriteAllText(outputFile + ".md5", file.Md5); - } + if (!string.IsNullOrEmpty(file.Md5)) + { + File.WriteAllText(outputFile + ".md5", file.Md5); + } - try - { - using var outputStream = File.OpenWrite(outputFile); - using var request = await this.client.GetStreamAsync(file.ZipUrl, cancellationToken).ConfigureAwait(false); - await request.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false); - } - catch (Exception downloadEx) - { - this.logger.LogError(downloadEx, "Failed to download file \"{uri}\" to \"{outputFile}\".", file.ZipUrl, outputFile); try { - File.Delete(outputFile); + using var outputStream = File.OpenWrite(outputFile); + using var request = await this.client.GetStreamAsync(file.ZipUrl, cancellationToken).ConfigureAwait(false); + await request.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false); } - catch (Exception removeEx) + catch (Exception downloadEx) { - this.logger.LogError(removeEx, "Failed to remove incomplete file \"{outputFile}\".", outputFile); - } - } + this.logger.LogError(downloadEx, "Attempt {attempt} failed to download file \"{uri}\" to \"{outputFile}\".", attempt, file.ZipUrl, outputFile); - this.logger.LogInformation("File \"{uri}\" successfully downloaded to \"{outputFile}\".", file.ZipUrl, outputFile); + if (attempt == options.MaxRetries) + { + this.logger.LogError(downloadEx, "Failed to download file \"{uri}\" to \"{outputFile}\".", file.ZipUrl, outputFile); + try + { + File.Delete(outputFile); + } + catch (Exception removeEx) + { + this.logger.LogError(removeEx, "Failed to remove incomplete file \"{outputFile}\".", outputFile); + } + throw; + } + else + { + await Task.Delay(options.DelayBetweenRetries, cancellationToken).ConfigureAwait(false); + } + } + this.logger.LogInformation("File \"{uri}\" successfully downloaded to \"{outputFile}\".", file.ZipUrl, outputFile); + } } #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously diff --git a/src/Models/DownloaderOptions.cs b/src/Models/DownloaderOptions.cs index 289cd54..8289da9 100644 --- a/src/Models/DownloaderOptions.cs +++ b/src/Models/DownloaderOptions.cs @@ -8,4 +8,7 @@ public record DownloaderOptions( bool Version, string? ProductVersion, bool SkipFileCheck, - string UserAgent) { } \ No newline at end of file + string UserAgent, + int MaxRetries, + int DelayBetweenRetries + ) { } \ No newline at end of file diff --git a/src/Program.cs b/src/Program.cs index eacb8a3..44013ac 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -24,6 +24,8 @@ public class Program /// Override target version to download some product. Advice: Use it with "customFeed". /// Skip compare of file sizes if a local file already exists. Existing file will be skipped to check and redownload. /// Set custom user agent via this feature flag. + /// Set custom count of download retries. + /// Set custom delay between retries (in milliseconds). static async Task Main( string? outputDir = default, Uri[]? customFeed = null, @@ -31,6 +33,8 @@ public class Program bool about = false, string? productVersion = null, bool skipFileCheck = false, + int maxRetries = 5, + int delayBetweenRetries = 2500, string userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:101.0) Gecko/20100101 Firefox/101.0") => await Host .CreateDefaultBuilder() @@ -60,7 +64,9 @@ public class Program about, productVersion, skipFileCheck, - userAgent)) + userAgent, + maxRetries, + delayBetweenRetries)) .AddHttpClient()) .RunConsoleAsync() .ConfigureAwait(false); diff --git a/src/atlassian-downloader.csproj b/src/atlassian-downloader.csproj index 493a125..1c2b4d9 100644 --- a/src/atlassian-downloader.csproj +++ b/src/atlassian-downloader.csproj @@ -12,6 +12,7 @@ enable Exe + true net8.0 false favicon.ico @@ -26,25 +27,25 @@ git https://github.com/EpicMorg/atlassian-downloader atlassian, donwloader, epicmorg - 2.0.0.0 - 2.0.0.0 - 2.0.0.0 - EpicMorg 2023 + 2.0.0.2 + 2.0.0.2 + 2.0.0.2 + EpicMorg 2024 Atlassian Downloader EpicMorg README.md EpicMorg.Atlassian.Downloader - - - - - - - - - + + + + + + + + + True