atlassian-downloader/src/DonloaderService.cs

203 lines
9.0 KiB
C#
Raw Normal View History

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
namespace EpicMorg.Atlassian.Downloader
{
class DonloaderService : IHostedService
{
private readonly ILogger<DonloaderService> logger;
private readonly DownloaderOptions options;
private readonly HttpClient client;
private readonly IHostApplicationLifetime hostApplicationLifetime;
public DonloaderService(IHostApplicationLifetime hostApplicationLifetime, ILogger<DonloaderService> logger, HttpClient client, DownloaderOptions options)
{
this.logger = logger;
this.client = client;
this.options = options;
this.hostApplicationLifetime = hostApplicationLifetime;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
this.SetConsoleTitle();
var feedUrls = this.GetFeedUrls();
logger.LogTrace($"Task started");
foreach (var feedUrl in feedUrls)
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
var (json, versions) = await this.GetJson(feedUrl, cancellationToken).ConfigureAwait(false);
switch (options.Action)
{
case DownloadAction.ShowRawJson:
Console.Out.WriteLine(json);
break;
case DownloadAction.Download:
await this.DownloadFilesFromFreed(feedUrl, versions, cancellationToken).ConfigureAwait(false);
break;
case DownloadAction.ListURLs:
foreach (var versionProg in versions)
{
foreach (var file in versionProg.Value)
{
Console.Out.WriteLine(file.ZipUrl);
}
}
break;
case DownloadAction.ListVersions:
foreach (var versionProg in versions)
{
foreach (var file in versionProg.Value)
{
Console.Out.WriteLine(file.Version);
}
}
break;
}
}
logger.LogInformation($"Complete");
this.hostApplicationLifetime.StopApplication();
}
private async Task<(string json, IDictionary<string, ResponseItem[]> versions)> GetJson(string feedUrl, CancellationToken cancellationToken)
{
var atlassianJson = await client.GetStringAsync(feedUrl, cancellationToken).ConfigureAwait(false);
var json = atlassianJson["downloads(".Length..^1];
var parsed = JsonSerializer.Deserialize<ResponseItem[]>(json, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
});
var versions = parsed.GroupBy(a => a.Version).ToDictionary(a => a.Key, a => a.ToArray());
return (json, versions);
}
private string[] GetFeedUrls() => options.CustomFeed != null
? options.CustomFeed.Select(a => a.ToString()).ToArray()
: new[] {
"https://my.atlassian.com/download/feeds/archived/bamboo.json",
"https://my.atlassian.com/download/feeds/archived/clover.json",
"https://my.atlassian.com/download/feeds/archived/confluence.json",
"https://my.atlassian.com/download/feeds/archived/crowd.json",
"https://my.atlassian.com/download/feeds/archived/crucible.json",
"https://my.atlassian.com/download/feeds/archived/fisheye.json",
"https://my.atlassian.com/download/feeds/archived/jira-core.json",
"https://my.atlassian.com/download/feeds/archived/jira-servicedesk.json",
"https://my.atlassian.com/download/feeds/archived/jira-software.json",
"https://my.atlassian.com/download/feeds/archived/jira.json",
"https://my.atlassian.com/download/feeds/archived/stash.json",
"https://my.atlassian.com/download/feeds/current/bamboo.json",
"https://my.atlassian.com/download/feeds/current/clover.json",
"https://my.atlassian.com/download/feeds/current/confluence.json",
"https://my.atlassian.com/download/feeds/current/crowd.json",
"https://my.atlassian.com/download/feeds/current/crucible.json",
"https://my.atlassian.com/download/feeds/current/fisheye.json",
"https://my.atlassian.com/download/feeds/current/jira-core.json",
"https://my.atlassian.com/download/feeds/current/jira-servicedesk.json",
"https://my.atlassian.com/download/feeds/current/jira-software.json",
"https://my.atlassian.com/download/feeds/current/stash.json",
"https://my.atlassian.com/download/feeds/eap/bamboo.json",
"https://my.atlassian.com/download/feeds/eap/confluence.json",
"https://my.atlassian.com/download/feeds/eap/jira.json",
"https://my.atlassian.com/download/feeds/eap/jira-servicedesk.json",
"https://my.atlassian.com/download/feeds/eap/stash.json"
};
private void SetConsoleTitle()
{
const string appBuildType =
#if DEBUG
"[Debug]"
#else
"[Release]"
#endif
;
var assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName();
Console.Title = $@"{assemblyName.Name} {assemblyName.Version} {appBuildType}";
}
private async Task DownloadFilesFromFreed(string feedUrl, IDictionary<string, ResponseItem[]> versions, CancellationToken cancellationToken)
{
var feedDir = Path.Combine(options.OutputDir, feedUrl[(feedUrl.LastIndexOf('/') + 1)..(feedUrl.LastIndexOf('.'))]);
logger.LogInformation($"Download from JSON \"{feedUrl}\" started");
foreach (var version in versions)
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
var directory = Path.Combine(feedDir, version.Key);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
foreach (var file in version.Value)
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
if (file.ZipUrl == null) { continue; }
var serverPath = file.ZipUrl.PathAndQuery;
var outputFile = Path.Combine(directory, serverPath[(serverPath.LastIndexOf("/") + 1)..]);
if (!File.Exists(outputFile))
{
await DownloadFile(file, outputFile, cancellationToken).ConfigureAwait(false);
}
else
{
logger.LogWarning($"File \"{outputFile}\" already exists. Download from \"{file.ZipUrl}\" skipped.");
}
}
}
logger.LogTrace($"All files from \"{feedUrl}\" successfully downloaded.");
}
private async Task DownloadFile(ResponseItem file, string outputFile, CancellationToken cancellationToken)
{
if (!string.IsNullOrEmpty(file.Md5))
{
File.WriteAllText(outputFile + ".md5", file.Md5);
}
try
{
using var outputStream = File.OpenWrite(outputFile);
using var request = await client.GetStreamAsync(file.ZipUrl, cancellationToken).ConfigureAwait(false);
await request.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false);
}
catch (Exception downloadEx)
{
logger.LogError(downloadEx, $"Failed to download file {file.ZipUrl} to {outputFile}.");
try
{
File.Delete(outputFile);
}
catch (Exception removeEx)
{
logger.LogError(removeEx, $"Failed to remove incomplete file {outputFile}.");
}
}
logger.LogInformation($"File \"{file.ZipUrl}\" successfully downloaded to \"{outputFile}\".");
}
public async Task StopAsync(CancellationToken cancellationToken) { }
}
}