using System; using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Humanizer; namespace Artemis.Core { /// /// Represents a plugin prerequisite action that downloads a file /// public class DownloadFileAction : PluginPrerequisiteAction { /// /// Creates a new instance of a copy folder action /// /// The name of the action /// The source URL to download /// The target file to save as (will be created if needed) public DownloadFileAction(string name, string url, string fileName) : base(name) { Url = url ?? throw new ArgumentNullException(nameof(url)); FileName = fileName ?? throw new ArgumentNullException(nameof(fileName)); ShowProgressBar = true; } /// /// Creates a new instance of a copy folder action /// /// The name of the action /// A function returning the URL to download /// The target file to save as (will be created if needed) public DownloadFileAction(string name, Func> urlFunction, string fileName) : base(name) { UrlFunction = urlFunction ?? throw new ArgumentNullException(nameof(urlFunction)); FileName = fileName ?? throw new ArgumentNullException(nameof(fileName)); ShowProgressBar = true; } /// /// Gets the source URL to download /// public string? Url { get; } /// /// Gets the function returning the URL to download /// public Func>? UrlFunction { get; } /// /// Gets the target file to save as (will be created if needed) /// public string FileName { get; } /// public override async Task Execute(CancellationToken cancellationToken) { using HttpClient client = new(); await using FileStream destinationStream = new(FileName, FileMode.OpenOrCreate); string url = Url ?? await UrlFunction(); void ProgressOnProgressReported(object? sender, EventArgs e) { if (Progress.ProgressPerSecond != 0) Status = $"Downloading {url} - {Progress.ProgressPerSecond.Bytes().Humanize("#.##")}/sec"; else Status = $"Downloading {url}"; } Progress.ProgressReported += ProgressOnProgressReported; // Get the http headers first to examine the content length using HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancellationToken); await using Stream download = await response.Content.ReadAsStreamAsync(cancellationToken); long? contentLength = response.Content.Headers.ContentLength; // Ignore progress reporting when no progress reporter was // passed or when the content length is unknown if (!contentLength.HasValue) { ProgressIndeterminate = true; await download.CopyToAsync(destinationStream, Progress, cancellationToken); ProgressIndeterminate = false; } else { ProgressIndeterminate = false; await download.CopyToAsync(contentLength.Value, destinationStream, Progress, cancellationToken); } cancellationToken.ThrowIfCancellationRequested(); Progress.ProgressReported -= ProgressOnProgressReported; Progress.Report((1, 1)); Status = "Finished downloading"; } } }