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:
parent
de6edaf565
commit
79894150d9
@ -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>
|
||||
|
||||
@ -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";
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user