1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Prerequisites - Fixed install dialog not updating to next action

Prerequisites - Finished download file action
Prerequisites - Added extract ZIP action
This commit is contained in:
Robert 2021-05-03 17:24:41 +02:00
parent de6edaf565
commit 79894150d9
4 changed files with 128 additions and 38 deletions

View File

@ -1,4 +1,4 @@
// Based on: https://www.codeproject.com/Tips/5274597/An-Improved-Stream-CopyToAsync-that-Reports-Progre
// Based on: https://www.codeproject.com/Tips/5274597/An-Improved-Stream-CopyToAsync-that-Reports-Progre
// The MIT License
//
// Copyright (c) 2020 honey the codewitch
@ -37,7 +37,7 @@ namespace Artemis.Core
private const int DefaultBufferSize = 81920;
/// <summary>
/// Copys a stream to another stream
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="sourceLength">The length of the source stream, if known - used for progress reporting</param>
@ -54,32 +54,33 @@ namespace Artemis.Core
IProgress<(long, long)> progress,
CancellationToken cancellationToken)
{
if (0 == bufferSize)
if (source == null)
throw new ArgumentNullException(nameof(source));
if (!source.CanRead)
throw new ArgumentException("Has to be readable", nameof(source));
if (destination == null)
throw new ArgumentNullException(nameof(destination));
if (!destination.CanWrite)
throw new ArgumentException("Has to be writable", nameof(destination));
if (bufferSize <= 0)
bufferSize = DefaultBufferSize;
byte[]? buffer = new byte[bufferSize];
if (0 > sourceLength && source.CanSeek)
sourceLength = source.Length - source.Position;
long totalBytesCopied = 0L;
if (null != progress)
progress.Report((totalBytesCopied, sourceLength));
int bytesRead = -1;
while (0 != bytesRead && !cancellationToken.IsCancellationRequested)
byte[] buffer = new byte[bufferSize];
long totalBytesRead = 0;
int bytesRead;
while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
{
bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken);
if (0 == bytesRead || cancellationToken.IsCancellationRequested)
break;
await destination.WriteAsync(buffer, 0, buffer.Length, cancellationToken);
totalBytesCopied += bytesRead;
progress?.Report((totalBytesCopied, sourceLength));
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
totalBytesRead += bytesRead;
progress?.Report((totalBytesRead, sourceLength));
}
if (0 < totalBytesCopied)
progress?.Report((totalBytesCopied, sourceLength));
progress?.Report((totalBytesRead, sourceLength));
cancellationToken.ThrowIfCancellationRequested();
}
/// <summary>
/// Copys a stream to another stream
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="sourceLength">The length of the source stream, if known - used for progress reporting</param>
@ -93,7 +94,7 @@ namespace Artemis.Core
}
/// <summary>
/// Copys a stream to another stream
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="destination">The destination <see cref="Stream" /> to copy to</param>
@ -106,7 +107,7 @@ namespace Artemis.Core
}
/// <summary>
/// Copys a stream to another stream
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="sourceLength">The length of the source stream, if known - used for progress reporting</param>
@ -119,7 +120,7 @@ namespace Artemis.Core
}
/// <summary>
/// Copys a stream to another stream
/// Copies a stream to another stream
/// </summary>
/// <param name="source">The source <see cref="Stream" /> to copy from</param>
/// <param name="destination">The destination <see cref="Stream" /> to copy to</param>

View File

@ -16,12 +16,12 @@ namespace Artemis.Core
/// Creates a new instance of a copy folder action
/// </summary>
/// <param name="name">The name of the action</param>
/// <param name="source">The source URL to download</param>
/// <param name="target">The target file to save as (will be created if needed)</param>
public DownloadFileAction(string name, string source, string target) : base(name)
/// <param name="url">The source URL to download</param>
/// <param name="fileName">The target file to save as (will be created if needed)</param>
public DownloadFileAction(string name, string url, string fileName) : base(name)
{
Source = source ?? throw new ArgumentNullException(nameof(source));
Target = target ?? throw new ArgumentNullException(nameof(target));
Url = url ?? throw new ArgumentNullException(nameof(url));
FileName = fileName ?? throw new ArgumentNullException(nameof(fileName));
ShowProgressBar = true;
}
@ -29,31 +29,31 @@ namespace Artemis.Core
/// <summary>
/// Gets the source URL to download
/// </summary>
public string Source { get; }
public string Url { get; }
/// <summary>
/// Gets the target file to save as (will be created if needed)
/// </summary>
public string Target { get; }
public string FileName { get; }
/// <inheritdoc />
public override async Task Execute(CancellationToken cancellationToken)
{
using HttpClient client = new();
await using FileStream destinationStream = File.Create(Target);
await using FileStream destinationStream = new(FileName, FileMode.OpenOrCreate);
void ProgressOnProgressReported(object? sender, EventArgs e)
{
if (Progress.ProgressPerSecond != 0)
Status = $"Downloading {Target} - {Progress.ProgressPerSecond.Bytes().Humanize("#.##")}/sec";
Status = $"Downloading {Url} - {Progress.ProgressPerSecond.Bytes().Humanize("#.##")}/sec";
else
Status = $"Downloading {Target}";
Status = $"Downloading {Url}";
}
Progress.ProgressReported += ProgressOnProgressReported;
// Get the http headers first to examine the content length
using HttpResponseMessage response = await client.GetAsync(Target, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
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;
@ -63,6 +63,7 @@ namespace Artemis.Core
{
ProgressIndeterminate = true;
await download.CopyToAsync(destinationStream, Progress, cancellationToken);
ProgressIndeterminate = false;
}
else
{
@ -70,8 +71,9 @@ namespace Artemis.Core
await download.CopyToAsync(contentLength.Value, destinationStream, Progress, cancellationToken);
}
cancellationToken.ThrowIfCancellationRequested();
Progress.ProgressReported -= ProgressOnProgressReported;
Progress.Report((1, 1));
Status = "Finished downloading";
}

View File

@ -0,0 +1,83 @@
using System;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace Artemis.Core
{
/// <summary>
/// Represents a plugin prerequisite action that extracts a ZIP file
/// </summary>
public class ExtractArchiveAction : PluginPrerequisiteAction
{
/// <summary>
/// Creates a new instance of <see cref="ExtractArchiveAction"/>.
/// </summary>
/// <param name="name">The name of the action</param>
/// <param name="fileName">The ZIP file to extract</param>
/// <param name="target">The folder into which to extract the file</param>
public ExtractArchiveAction(string name, string fileName, string target) : base(name)
{
FileName = fileName ?? throw new ArgumentNullException(nameof(fileName));
Target = target ?? throw new ArgumentNullException(nameof(target));
ShowProgressBar = true;
}
/// <summary>
/// Gets the file to extract
/// </summary>
public string FileName { get; }
/// <summary>
/// Gets the folder into which to extract the file
/// </summary>
public string Target { get; }
/// <inheritdoc />
public override async Task Execute(CancellationToken cancellationToken)
{
using HttpClient client = new();
ShowSubProgressBar = true;
Status = $"Extracting {FileName}";
Utilities.CreateAccessibleDirectory(Target);
await using (FileStream fileStream = new(FileName, FileMode.Open))
{
ZipArchive archive = new(fileStream);
long count = 0;
foreach (ZipArchiveEntry entry in archive.Entries)
{
await using Stream unzippedEntryStream = entry.Open();
Progress.Report((count, archive.Entries.Count));
if (entry.Length > 0)
{
string path = Path.Combine(Target, entry.FullName);
CreateDirectoryForFile(path);
await using Stream extractStream = new FileStream(path, FileMode.OpenOrCreate);
await unzippedEntryStream.CopyToAsync(entry.Length, extractStream, SubProgress, cancellationToken);
}
count++;
}
}
Progress.Report((1, 1));
ShowSubProgressBar = false;
Status = "Finished extracting";
}
private static void CreateDirectoryForFile(string path)
{
string? directory = Path.GetDirectoryName(path);
if (directory == null)
throw new ArtemisCoreException($"Failed to get directory from path {path}");
Utilities.CreateAccessibleDirectory(directory);
}
}
}

View File

@ -114,7 +114,11 @@ namespace Artemis.UI.Screens.Plugins
private void ActivateCurrentAction()
{
ActiveItem = Items.FirstOrDefault(i => i.Action == PluginPrerequisite.CurrentAction);
PluginPrerequisiteActionViewModel newActiveItem = Items.FirstOrDefault(i => i.Action == PluginPrerequisite.CurrentAction);
if (newActiveItem == null)
return;
ActiveItem = newActiveItem;
NotifyOfPropertyChange(nameof(ActiveStemNumber));
}
@ -123,14 +127,14 @@ namespace Artemis.UI.Screens.Plugins
/// <inheritdoc />
protected override void OnClose()
{
PluginPrerequisite.PropertyChanged += PluginPrerequisiteOnPropertyChanged;
PluginPrerequisite.PropertyChanged -= PluginPrerequisiteOnPropertyChanged;
base.OnClose();
}
/// <inheritdoc />
protected override void OnInitialActivate()
{
PluginPrerequisite.PropertyChanged -= PluginPrerequisiteOnPropertyChanged;
PluginPrerequisite.PropertyChanged += PluginPrerequisiteOnPropertyChanged;
// Could be slow so take it off of the UI thread
Task.Run(() => IsMet = PluginPrerequisite.IsMet());