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