mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Improve HttpDownloadAsync function & Use it in PluginManager plugin
This commit is contained in:
parent
029cb38c61
commit
8eb5a4dfca
5 changed files with 67 additions and 71 deletions
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
|
@ -121,10 +120,10 @@ namespace Flow.Launcher.Core.Plugin.JsonRPCV2Models
|
|||
return _api.HttpGetStreamAsync(url, token);
|
||||
}
|
||||
|
||||
public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath,
|
||||
public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
return _api.HttpDownloadAsync(url, filePath, token);
|
||||
return _api.HttpDownloadAsync(url, filePath, reportProgress, token);
|
||||
}
|
||||
|
||||
public void AddActionKeyword(string pluginId, string newActionKeyword)
|
||||
|
|
@ -162,13 +161,11 @@ namespace Flow.Launcher.Core.Plugin.JsonRPCV2Models
|
|||
_api.OpenDirectory(DirectoryPath, FileNameOrFilePath);
|
||||
}
|
||||
|
||||
|
||||
public void OpenUrl(string url, bool? inPrivate = null)
|
||||
{
|
||||
_api.OpenUrl(url, inPrivate);
|
||||
}
|
||||
|
||||
|
||||
public void OpenAppUri(string appUri)
|
||||
{
|
||||
_api.OpenAppUri(appUri);
|
||||
|
|
|
|||
|
|
@ -83,15 +83,50 @@ namespace Flow.Launcher.Infrastructure.Http
|
|||
}
|
||||
}
|
||||
|
||||
public static async Task DownloadAsync([NotNull] string url, [NotNull] string filePath, CancellationToken token = default)
|
||||
public static async Task DownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null, CancellationToken token = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
|
||||
|
||||
if (response.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
await using var fileStream = new FileStream(filePath, FileMode.CreateNew);
|
||||
await response.Content.CopyToAsync(fileStream, token);
|
||||
var totalBytes = response.Content.Headers.ContentLength ?? -1L;
|
||||
var canReportProgress = totalBytes != -1;
|
||||
|
||||
if (canReportProgress && reportProgress != null)
|
||||
{
|
||||
await using var contentStream = await response.Content.ReadAsStreamAsync(token);
|
||||
await using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true);
|
||||
|
||||
var buffer = new byte[8192];
|
||||
long totalRead = 0;
|
||||
int read;
|
||||
double progressValue = 0;
|
||||
|
||||
reportProgress(0);
|
||||
|
||||
while ((read = await contentStream.ReadAsync(buffer, token)) > 0)
|
||||
{
|
||||
await fileStream.WriteAsync(buffer.AsMemory(0, read), token);
|
||||
totalRead += read;
|
||||
|
||||
progressValue = totalRead * 100.0 / totalBytes;
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
else
|
||||
reportProgress(progressValue);
|
||||
}
|
||||
|
||||
if (progressValue < 100)
|
||||
reportProgress(100);
|
||||
}
|
||||
else
|
||||
{
|
||||
await using var fileStream = new FileStream(filePath, FileMode.CreateNew);
|
||||
await response.Content.CopyToAsync(fileStream, token);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -181,9 +181,13 @@ namespace Flow.Launcher.Plugin
|
|||
/// </summary>
|
||||
/// <param name="url">URL to download file</param>
|
||||
/// <param name="filePath">path to save downloaded file</param>
|
||||
/// <param name="reportProgress">
|
||||
/// Action to report progress. The input of the action is the progress value which is a double value between 0 and 100.
|
||||
/// It will be called if url support range request and the reportProgress is not null.
|
||||
/// </param>
|
||||
/// <param name="token">place to store file</param>
|
||||
/// <returns>Task showing the progress</returns>
|
||||
Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, CancellationToken token = default);
|
||||
Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null, CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// Add ActionKeyword for specific plugin
|
||||
|
|
|
|||
|
|
@ -164,8 +164,8 @@ namespace Flow.Launcher
|
|||
public Task<Stream> HttpGetStreamAsync(string url, CancellationToken token = default) =>
|
||||
Http.GetStreamAsync(url);
|
||||
|
||||
public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath,
|
||||
CancellationToken token = default) => Http.DownloadAsync(url, filePath, token);
|
||||
public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null,
|
||||
CancellationToken token = default) => Http.DownloadAsync(url, filePath, reportProgress, token);
|
||||
|
||||
public void AddActionKeyword(string pluginId, string newActionKeyword) =>
|
||||
PluginManager.AddActionKeyword(pluginId, newActionKeyword);
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
{
|
||||
internal class PluginsManager
|
||||
{
|
||||
private static readonly HttpClient HttpClient = new();
|
||||
|
||||
private const string zip = "zip";
|
||||
|
||||
private PluginInitContext Context { get; set; }
|
||||
|
|
@ -144,75 +142,37 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
|
||||
var filePath = Path.Combine(Path.GetTempPath(), downloadFilename);
|
||||
|
||||
var downloadCancelled = false;
|
||||
var exceptionHappened = false;
|
||||
try
|
||||
{
|
||||
using var cts = new CancellationTokenSource();
|
||||
|
||||
if (!plugin.IsFromLocalInstallPath)
|
||||
{
|
||||
if (File.Exists(filePath))
|
||||
File.Delete(filePath);
|
||||
|
||||
using var cts = new CancellationTokenSource();
|
||||
using var response = await HttpClient.GetAsync(plugin.UrlDownload, HttpCompletionOption.ResponseHeadersRead, cts.Token).ConfigureAwait(false);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var totalBytes = response.Content.Headers.ContentLength ?? -1L;
|
||||
var canReportProgress = totalBytes != -1;
|
||||
|
||||
var prgBoxTitle = $"{Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin")} {plugin.Name}";
|
||||
if (canReportProgress)
|
||||
{
|
||||
await Context.API.ShowProgressBoxAsync(prgBoxTitle,
|
||||
async (reportProgress) =>
|
||||
await Context.API.ShowProgressBoxAsync(prgBoxTitle,
|
||||
async (reportProgress) =>
|
||||
{
|
||||
if (reportProgress == null)
|
||||
{
|
||||
if (reportProgress == null)
|
||||
{
|
||||
// when reportProgress is null, it means there is expcetion with the progress box
|
||||
// so we record it with exceptionHappened and return so that progress box will close instantly
|
||||
exceptionHappened = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
await using var contentStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
||||
await using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true);
|
||||
|
||||
var buffer = new byte[8192];
|
||||
long totalRead = 0;
|
||||
int read;
|
||||
|
||||
while ((read = await contentStream.ReadAsync(buffer).ConfigureAwait(false)) > 0)
|
||||
{
|
||||
await fileStream.WriteAsync(buffer.AsMemory(0, read)).ConfigureAwait(false);
|
||||
totalRead += read;
|
||||
|
||||
var progressValue = totalRead * 100 / totalBytes;
|
||||
|
||||
// check if user cancelled download before reporting progress
|
||||
if (downloadCancelled)
|
||||
return;
|
||||
else
|
||||
reportProgress(progressValue);
|
||||
}
|
||||
}
|
||||
},
|
||||
() =>
|
||||
// when reportProgress is null, it means there is expcetion with the progress box
|
||||
// so we record it with exceptionHappened and return so that progress box will close instantly
|
||||
exceptionHappened = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
cts.Cancel();
|
||||
downloadCancelled = true;
|
||||
});
|
||||
await Http.DownloadAsync(plugin.UrlDownload, filePath, reportProgress, cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
}, cts.Cancel);
|
||||
|
||||
// if exception happened while downloading and user does not cancel downloading,
|
||||
// we need to redownload the plugin
|
||||
if (exceptionHappened && (!downloadCancelled))
|
||||
await Http.DownloadAsync(plugin.UrlDownload, filePath).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await Http.DownloadAsync(plugin.UrlDownload, filePath).ConfigureAwait(false);
|
||||
}
|
||||
// if exception happened while downloading and user does not cancel downloading,
|
||||
// we need to redownload the plugin
|
||||
if (exceptionHappened && (!cts.IsCancellationRequested))
|
||||
await Http.DownloadAsync(plugin.UrlDownload, filePath, null, cts.Token).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -220,7 +180,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
}
|
||||
|
||||
// check if user cancelled download before installing plugin
|
||||
if (downloadCancelled)
|
||||
if (cts.IsCancellationRequested)
|
||||
return;
|
||||
else
|
||||
Install(plugin, filePath);
|
||||
|
|
|
|||
Loading…
Reference in a new issue