From 4ea5dd5ad2ad6d4869d57c8aed1e187d81662135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 13 Oct 2020 20:54:00 +0800 Subject: [PATCH 01/17] Move Old HttpWebRequest to HttpClient Instance (solve connection timeout) --- Flow.Launcher.Core/Updater.cs | 2 +- Flow.Launcher.Infrastructure/Http/Http.cs | 77 ++++++++++++++--------- 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 99d48275a45..4ad8b19be25 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -139,7 +139,7 @@ private async Task GitHubUpdateManager(string repository) var latest = releases.Where(r => !r.Prerelease).OrderByDescending(r => r.PublishedAt).First(); var latestUrl = latest.HtmlUrl.Replace("/tag/", "/download/"); - var client = new WebClient { Proxy = Http.WebProxy() }; + var client = new WebClient { Proxy = Http.WebProxy }; var downloader = new FileDownloader(client); var manager = new UpdateManager(latestUrl, urlDownloader: downloader); diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index b7d274205ad..038362a0d99 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -13,6 +13,13 @@ public static class Http { private const string UserAgent = @"Mozilla/5.0 (Trident/7.0; rv:11.0) like Gecko"; + private static HttpClient client; + private static SocketsHttpHandler socketsHttpHandler = new SocketsHttpHandler() + { + UseProxy = true, + Proxy = WebProxy + }; + static Http() { // need to be added so it would work on a win10 machine @@ -20,36 +27,55 @@ static Http() ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; + + client.DefaultRequestHeaders.Add("User-Agent", UserAgent); + + } + private static HttpProxy proxy; + public static HttpProxy Proxy + { + private get + { + return proxy; + } + set + { + proxy = value; + UpdateProxy(); + } } - public static HttpProxy Proxy { private get; set; } - public static IWebProxy WebProxy() + public static WebProxy WebProxy { get; private set; } + + /// + /// Update the Address of the Proxy to modify the client Proxy + /// + public static void UpdateProxy() + // TODO: need test with a proxy { if (Proxy != null && Proxy.Enabled && !string.IsNullOrEmpty(Proxy.Server)) { if (string.IsNullOrEmpty(Proxy.UserName) || string.IsNullOrEmpty(Proxy.Password)) { - var webProxy = new WebProxy(Proxy.Server, Proxy.Port); - return webProxy; + WebProxy.Address = new Uri($"http://{Proxy.Server}:{Proxy.Port}"); + WebProxy.Credentials = null; } else { - var webProxy = new WebProxy(Proxy.Server, Proxy.Port) - { - Credentials = new NetworkCredential(Proxy.UserName, Proxy.Password) - }; - return webProxy; + WebProxy.Address = new Uri($"http://{Proxy.Server}:{Proxy.Port}"); + WebProxy.Credentials = new NetworkCredential(Proxy.UserName, Proxy.Password); } } else { - return WebRequest.GetSystemWebProxy(); + WebProxy.Address = new WebProxy().Address; + WebProxy.Credentials = null; } } public static void Download([NotNull] string url, [NotNull] string filePath) { - var client = new WebClient { Proxy = WebProxy() }; + var client = new WebClient { Proxy = WebProxy }; client.Headers.Add("user-agent", UserAgent); client.DownloadFile(url, filePath); } @@ -57,26 +83,17 @@ public static void Download([NotNull] string url, [NotNull] string filePath) public static async Task Get([NotNull] string url, string encoding = "UTF-8") { Log.Debug($"|Http.Get|Url <{url}>"); - var request = WebRequest.CreateHttp(url); - request.Method = "GET"; - request.Timeout = 1000; - request.Proxy = WebProxy(); - request.UserAgent = UserAgent; - var response = await request.GetResponseAsync() as HttpWebResponse; - response = response.NonNull(); - var stream = response.GetResponseStream().NonNull(); - - using (var reader = new StreamReader(stream, Encoding.GetEncoding(encoding))) + var response = await client.GetAsync(url); + using var stream = await response.Content.ReadAsStreamAsync(); + using var reader = new StreamReader(stream, Encoding.GetEncoding(encoding)); + var content = await reader.ReadToEndAsync(); + if (response.StatusCode == HttpStatusCode.OK) { - var content = await reader.ReadToEndAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - return content; - } - else - { - throw new HttpRequestException($"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); - } + return content; + } + else + { + throw new HttpRequestException($"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); } } } From a16cc5be8db3b5d52acf12565b029439c8d1a921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 13 Oct 2020 20:54:00 +0800 Subject: [PATCH 02/17] Move Old HttpWebRequest to HttpClient Instance (solve connection timeout) --- Flow.Launcher.Core/Updater.cs | 2 +- Flow.Launcher.Infrastructure/Http/Http.cs | 78 ++++++++++++++--------- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 99d48275a45..4ad8b19be25 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -139,7 +139,7 @@ private async Task GitHubUpdateManager(string repository) var latest = releases.Where(r => !r.Prerelease).OrderByDescending(r => r.PublishedAt).First(); var latestUrl = latest.HtmlUrl.Replace("/tag/", "/download/"); - var client = new WebClient { Proxy = Http.WebProxy() }; + var client = new WebClient { Proxy = Http.WebProxy }; var downloader = new FileDownloader(client); var manager = new UpdateManager(latestUrl, urlDownloader: downloader); diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index b7d274205ad..81c07eff7ea 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -6,6 +6,7 @@ using JetBrains.Annotations; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; +using System; namespace Flow.Launcher.Infrastructure.Http { @@ -13,6 +14,13 @@ public static class Http { private const string UserAgent = @"Mozilla/5.0 (Trident/7.0; rv:11.0) like Gecko"; + private static HttpClient client; + private static SocketsHttpHandler socketsHttpHandler = new SocketsHttpHandler() + { + UseProxy = true, + Proxy = WebProxy + }; + static Http() { // need to be added so it would work on a win10 machine @@ -20,36 +28,55 @@ static Http() ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; + + client.DefaultRequestHeaders.Add("User-Agent", UserAgent); + + } + private static HttpProxy proxy; + public static HttpProxy Proxy + { + private get + { + return proxy; + } + set + { + proxy = value; + UpdateProxy(); + } } - public static HttpProxy Proxy { private get; set; } - public static IWebProxy WebProxy() + public static WebProxy WebProxy { get; private set; } + + /// + /// Update the Address of the Proxy to modify the client Proxy + /// + public static void UpdateProxy() + // TODO: need test with a proxy { if (Proxy != null && Proxy.Enabled && !string.IsNullOrEmpty(Proxy.Server)) { if (string.IsNullOrEmpty(Proxy.UserName) || string.IsNullOrEmpty(Proxy.Password)) { - var webProxy = new WebProxy(Proxy.Server, Proxy.Port); - return webProxy; + WebProxy.Address = new Uri($"http://{Proxy.Server}:{Proxy.Port}"); + WebProxy.Credentials = null; } else { - var webProxy = new WebProxy(Proxy.Server, Proxy.Port) - { - Credentials = new NetworkCredential(Proxy.UserName, Proxy.Password) - }; - return webProxy; + WebProxy.Address = new Uri($"http://{Proxy.Server}:{Proxy.Port}"); + WebProxy.Credentials = new NetworkCredential(Proxy.UserName, Proxy.Password); } } else { - return WebRequest.GetSystemWebProxy(); + WebProxy.Address = new WebProxy().Address; + WebProxy.Credentials = null; } } public static void Download([NotNull] string url, [NotNull] string filePath) { - var client = new WebClient { Proxy = WebProxy() }; + var client = new WebClient { Proxy = WebProxy }; client.Headers.Add("user-agent", UserAgent); client.DownloadFile(url, filePath); } @@ -57,26 +84,17 @@ public static void Download([NotNull] string url, [NotNull] string filePath) public static async Task Get([NotNull] string url, string encoding = "UTF-8") { Log.Debug($"|Http.Get|Url <{url}>"); - var request = WebRequest.CreateHttp(url); - request.Method = "GET"; - request.Timeout = 1000; - request.Proxy = WebProxy(); - request.UserAgent = UserAgent; - var response = await request.GetResponseAsync() as HttpWebResponse; - response = response.NonNull(); - var stream = response.GetResponseStream().NonNull(); - - using (var reader = new StreamReader(stream, Encoding.GetEncoding(encoding))) + var response = await client.GetAsync(url); + using var stream = await response.Content.ReadAsStreamAsync(); + using var reader = new StreamReader(stream, Encoding.GetEncoding(encoding)); + var content = await reader.ReadToEndAsync(); + if (response.StatusCode == HttpStatusCode.OK) { - var content = await reader.ReadToEndAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - return content; - } - else - { - throw new HttpRequestException($"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); - } + return content; + } + else + { + throw new HttpRequestException($"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); } } } From c55e889f4fb37aa2624eec4523cbcd94cadc3293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 14 Oct 2020 11:29:12 +0800 Subject: [PATCH 03/17] Change Download to HttpClient as well (which change it to async as well) --- Flow.Launcher.Infrastructure/Http/Http.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 81c07eff7ea..34665217cb6 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -29,6 +29,7 @@ static Http() | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; + client = new HttpClient(socketsHttpHandler, false); client.DefaultRequestHeaders.Add("User-Agent", UserAgent); } @@ -46,7 +47,7 @@ private get } } - public static WebProxy WebProxy { get; private set; } + public static WebProxy WebProxy { get; private set; } = new WebProxy(); /// /// Update the Address of the Proxy to modify the client Proxy @@ -74,11 +75,18 @@ public static void UpdateProxy() } } - public static void Download([NotNull] string url, [NotNull] string filePath) + public async static Task Download([NotNull] string url, [NotNull] string filePath) { - var client = new WebClient { Proxy = WebProxy }; - client.Headers.Add("user-agent", UserAgent); - client.DownloadFile(url, filePath); + using var response = await client.GetAsync(url); + if (response.StatusCode == HttpStatusCode.OK) + { + using var fileStream = new FileStream(filePath, FileMode.CreateNew); + await response.Content.CopyToAsync(fileStream); + } + else + { + throw new WebException($"Error code <{response.StatusCode}> returned from <{url}>"); + } } public static async Task Get([NotNull] string url, string encoding = "UTF-8") From 424d757add58ccb38b50332b8a7597e8768b84bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 14 Oct 2020 11:29:38 +0800 Subject: [PATCH 04/17] Add Task.Run due to the change of async download --- .../Main.cs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginManagement/Main.cs index e1b631517e2..0255216a006 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManagement/Main.cs @@ -144,7 +144,7 @@ private List ResultForInstallPlugin(Query query) IcoPath = "Images\\plugin.png", TitleHighlightData = StringMatcher.FuzzySearch(query.SecondSearch, r.name).MatchData, SubTitleHighlightData = StringMatcher.FuzzySearch(query.SecondSearch, r.description).MatchData, - Action = c => + Action = _ => { MessageBoxResult result = MessageBox.Show("Are you sure you wish to install the \'" + r.name + "\' plugin", "Install plugin", MessageBoxButton.YesNo); @@ -157,17 +157,19 @@ private List ResultForInstallPlugin(Query query) string pluginUrl = APIBASE + "/media/" + r1.plugin_file; - try + Task.Run(async () => { - Http.Download(pluginUrl, filePath); - } - catch (WebException e) - { - context.API.ShowMsg($"PluginManagement.ResultForInstallPlugin: download failed for <{r.name}>"); - Log.Exception($"|PluginManagement.ResultForInstallPlugin|download failed for <{r.name}>", e); - return false; - } - context.API.InstallPlugin(filePath); + try + { + await Http.Download(pluginUrl, filePath); + context.API.InstallPlugin(filePath); + } + catch (WebException e) + { + context.API.ShowMsg($"PluginManagement.ResultForInstallPlugin: download failed for <{r.name}>"); + Log.Exception($"|PluginManagement.ResultForInstallPlugin|download failed for <{r.name}>", e); + } + }); } return false; } From 85f5766022ec2282dd7cf2595c48785964e3433f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Mon, 21 Dec 2020 19:30:18 +0800 Subject: [PATCH 05/17] Optimize a few code --- Flow.Launcher.Infrastructure/Http/Http.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 34665217cb6..4ec4f887f2a 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -75,12 +75,12 @@ public static void UpdateProxy() } } - public async static Task Download([NotNull] string url, [NotNull] string filePath) + public static async Task Download([NotNull] string url, [NotNull] string filePath) { using var response = await client.GetAsync(url); if (response.StatusCode == HttpStatusCode.OK) { - using var fileStream = new FileStream(filePath, FileMode.CreateNew); + await using var fileStream = new FileStream(filePath, FileMode.CreateNew); await response.Content.CopyToAsync(fileStream); } else @@ -93,7 +93,7 @@ public static async Task Get([NotNull] string url, string encoding = "UT { Log.Debug($"|Http.Get|Url <{url}>"); var response = await client.GetAsync(url); - using var stream = await response.Content.ReadAsStreamAsync(); + await using var stream = await response.Content.ReadAsStreamAsync(); using var reader = new StreamReader(stream, Encoding.GetEncoding(encoding)); var content = await reader.ReadToEndAsync(); if (response.StatusCode == HttpStatusCode.OK) From 96609f797e672021664c788f1d0acde1afec40ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Mon, 21 Dec 2020 19:42:50 +0800 Subject: [PATCH 06/17] Change the place of Wait in PluginManifest to make code more elegent --- .../Models/PluginsManifest.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs index 29022171007..13a5ae2cab7 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs @@ -10,21 +10,19 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models internal class PluginsManifest { internal List UserPlugins { get; private set; } + internal PluginsManifest() { - DownloadManifest(); + DownloadManifest().Wait(); } - private void DownloadManifest() + private async Task DownloadManifest() { var json = string.Empty; try { - var t = Task.Run( - async () => - json = await Http.Get("https://raw.githubusercontent.com/Flow-Launcher/Flow.Launcher.PluginsManifest/main/plugins.json")); - - t.Wait(); + json = await Http.Get( + "https://raw.githubusercontent.com/Flow-Launcher/Flow.Launcher.PluginsManifest/main/plugins.json"); UserPlugins = JsonConvert.DeserializeObject>(json); } @@ -34,7 +32,6 @@ private void DownloadManifest() UserPlugins = new List(); } - } } -} +} \ No newline at end of file From 5ab8c4faa3bc858af489096e3b8f4e9f9e290d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Mon, 21 Dec 2020 20:55:28 +0800 Subject: [PATCH 07/17] Update Proxy every time calling a http request method since the proxy setting won't update automatically without action --- Flow.Launcher.Infrastructure/Http/Http.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 4ec4f887f2a..a88d868a691 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -47,7 +47,14 @@ private get } } - public static WebProxy WebProxy { get; private set; } = new WebProxy(); + private static WebProxy _proxy = new WebProxy(); + public static WebProxy WebProxy { + get + { + UpdateProxy(); + return _proxy; + } + } /// /// Update the Address of the Proxy to modify the client Proxy @@ -77,6 +84,7 @@ public static void UpdateProxy() public static async Task Download([NotNull] string url, [NotNull] string filePath) { + UpdateProxy(); using var response = await client.GetAsync(url); if (response.StatusCode == HttpStatusCode.OK) { @@ -91,6 +99,7 @@ public static async Task Download([NotNull] string url, [NotNull] string filePat public static async Task Get([NotNull] string url, string encoding = "UTF-8") { + UpdateProxy(); Log.Debug($"|Http.Get|Url <{url}>"); var response = await client.GetAsync(url); await using var stream = await response.Content.ReadAsStreamAsync(); From 88fa862277eeff5a49058e72f3ec157ec817aa0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Tue, 22 Dec 2020 00:31:00 +0800 Subject: [PATCH 08/17] Use event triggered update method instead of checking Proxy every time doing Http request --- Flow.Launcher.Infrastructure/Http/Http.cs | 64 +++++++-------- .../UserSettings/HttpProxy.cs | 81 +++++++++++++++++-- 2 files changed, 105 insertions(+), 40 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index a88d868a691..8fe910c0cdc 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -7,6 +7,7 @@ using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using System; +using System.ComponentModel; namespace Flow.Launcher.Infrastructure.Http { @@ -15,6 +16,7 @@ public static class Http private const string UserAgent = @"Mozilla/5.0 (Trident/7.0; rv:11.0) like Gecko"; private static HttpClient client; + private static SocketsHttpHandler socketsHttpHandler = new SocketsHttpHandler() { UseProxy = true, @@ -31,60 +33,54 @@ static Http() client = new HttpClient(socketsHttpHandler, false); client.DefaultRequestHeaders.Add("User-Agent", UserAgent); - } + private static HttpProxy proxy; + public static HttpProxy Proxy { - private get - { - return proxy; - } + private get { return proxy; } set { proxy = value; - UpdateProxy(); + proxy.PropertyChanged += UpdateProxy; } } - private static WebProxy _proxy = new WebProxy(); - public static WebProxy WebProxy { - get - { - UpdateProxy(); - return _proxy; - } + private static readonly WebProxy _proxy = new WebProxy(); + + public static WebProxy WebProxy + { + get { return _proxy; } } /// /// Update the Address of the Proxy to modify the client Proxy /// - public static void UpdateProxy() - // TODO: need test with a proxy + public static void UpdateProxy(ProxyProperty property) { - if (Proxy != null && Proxy.Enabled && !string.IsNullOrEmpty(Proxy.Server)) + (_proxy.Address, _proxy.Credentials) = property switch { - if (string.IsNullOrEmpty(Proxy.UserName) || string.IsNullOrEmpty(Proxy.Password)) + ProxyProperty.Enabled => (Proxy.Enabled) switch { - WebProxy.Address = new Uri($"http://{Proxy.Server}:{Proxy.Port}"); - WebProxy.Credentials = null; - } - else - { - WebProxy.Address = new Uri($"http://{Proxy.Server}:{Proxy.Port}"); - WebProxy.Credentials = new NetworkCredential(Proxy.UserName, Proxy.Password); - } - } - else - { - WebProxy.Address = new WebProxy().Address; - WebProxy.Credentials = null; - } + true => Proxy.UserName switch + { + var userName when !string.IsNullOrEmpty(userName) => + (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), null), + _ => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), + new NetworkCredential(Proxy.UserName, Proxy.Password)) + }, + false => (null, null) + }, + ProxyProperty.Server => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), _proxy.Credentials), + ProxyProperty.Port => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), _proxy.Credentials), + ProxyProperty.UserName => (_proxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)), + ProxyProperty.Password => (_proxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)) + }; } public static async Task Download([NotNull] string url, [NotNull] string filePath) { - UpdateProxy(); using var response = await client.GetAsync(url); if (response.StatusCode == HttpStatusCode.OK) { @@ -99,7 +95,6 @@ public static async Task Download([NotNull] string url, [NotNull] string filePat public static async Task Get([NotNull] string url, string encoding = "UTF-8") { - UpdateProxy(); Log.Debug($"|Http.Get|Url <{url}>"); var response = await client.GetAsync(url); await using var stream = await response.Content.ReadAsStreamAsync(); @@ -111,7 +106,8 @@ public static async Task Get([NotNull] string url, string encoding = "UT } else { - throw new HttpRequestException($"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); + throw new HttpRequestException( + $"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); } } } diff --git a/Flow.Launcher.Infrastructure/UserSettings/HttpProxy.cs b/Flow.Launcher.Infrastructure/UserSettings/HttpProxy.cs index c1b0c1dd7fe..21319352633 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/HttpProxy.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/HttpProxy.cs @@ -1,11 +1,80 @@ -namespace Flow.Launcher.Infrastructure.UserSettings +using System.ComponentModel; + +namespace Flow.Launcher.Infrastructure.UserSettings { + public enum ProxyProperty + { + Enabled, + Server, + Port, + UserName, + Password + } + public class HttpProxy { - public bool Enabled { get; set; } = false; - public string Server { get; set; } - public int Port { get; set; } - public string UserName { get; set; } - public string Password { get; set; } + private bool _enabled = false; + private string _server; + private int _port; + private string _userName; + private string _password; + + public bool Enabled + { + get => _enabled; + set + { + _enabled = value; + OnPropertyChanged(ProxyProperty.Enabled); + } + } + + public string Server + { + get => _server; + set + { + _server = value; + OnPropertyChanged(ProxyProperty.Server); + } + } + + public int Port + { + get => _port; + set + { + _port = value; + OnPropertyChanged(ProxyProperty.Port); + } + } + + public string UserName + { + get => _userName; + set + { + _userName = value; + OnPropertyChanged(ProxyProperty.UserName); + } + } + + public string Password + { + get => _password; + set + { + _password = value; + OnPropertyChanged(ProxyProperty.Password); + } + } + + public delegate void ProxyPropertyChangedHandler(ProxyProperty property); + public event ProxyPropertyChangedHandler PropertyChanged; + + private void OnPropertyChanged(ProxyProperty property) + { + PropertyChanged?.Invoke(property); + } } } \ No newline at end of file From cfa93a2cc60808b84a131852a82f3e26ce1a4339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 17:13:31 +0800 Subject: [PATCH 09/17] Add GetStreamAsync method --- Flow.Launcher.Infrastructure/Http/Http.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 74e335d3275..11d922aa12e 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -110,5 +110,12 @@ public static async Task Get([NotNull] string url, string encoding = "UT $"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); } } + + public static async Task GetStreamAsync([NotNull] string url) + { + Log.Debug($"|Http.Get|Url <{url}>"); + var response = await client.GetAsync(url); + return await response.Content.ReadAsStreamAsync(); + } } } From a806f7d05adc9beb7419e555921192e094c10539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 17:14:13 +0800 Subject: [PATCH 10/17] Change exception type --- Flow.Launcher.Infrastructure/Http/Http.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 11d922aa12e..a98ead68773 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -89,7 +89,7 @@ public static async Task Download([NotNull] string url, [NotNull] string filePat } else { - throw new WebException($"Error code <{response.StatusCode}> returned from <{url}>"); + throw new HttpRequestException($"Error code <{response.StatusCode}> returned from <{url}>"); } } From 4d5119f17d2f5b307dd7eb33384e63ee31b48c27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 17:15:34 +0800 Subject: [PATCH 11/17] Add out of bound exception for pattern matching --- Flow.Launcher.Infrastructure/Http/Http.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index a98ead68773..040939e725d 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -61,7 +61,7 @@ public static void UpdateProxy(ProxyProperty property) { (_proxy.Address, _proxy.Credentials) = property switch { - ProxyProperty.Enabled => (Proxy.Enabled) switch + ProxyProperty.Enabled => Proxy.Enabled switch { true => Proxy.UserName switch { @@ -75,7 +75,8 @@ public static void UpdateProxy(ProxyProperty property) ProxyProperty.Server => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), _proxy.Credentials), ProxyProperty.Port => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), _proxy.Credentials), ProxyProperty.UserName => (_proxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)), - ProxyProperty.Password => (_proxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)) + ProxyProperty.Password => (_proxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)), + _ => throw new ArgumentOutOfRangeException() }; } From e364b84b8458aa8df058fa9cf4507b2699d3224a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 17:16:44 +0800 Subject: [PATCH 12/17] Use auto property --- Flow.Launcher.Infrastructure/Http/Http.cs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 040939e725d..3d056b28b90 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -47,19 +47,14 @@ public static HttpProxy Proxy } } - private static readonly WebProxy _proxy = new WebProxy(); - - public static WebProxy WebProxy - { - get { return _proxy; } - } + public static WebProxy WebProxy { get; } = new WebProxy(); /// /// Update the Address of the Proxy to modify the client Proxy /// public static void UpdateProxy(ProxyProperty property) { - (_proxy.Address, _proxy.Credentials) = property switch + (WebProxy.Address, WebProxy.Credentials) = property switch { ProxyProperty.Enabled => Proxy.Enabled switch { @@ -72,10 +67,10 @@ public static void UpdateProxy(ProxyProperty property) }, false => (null, null) }, - ProxyProperty.Server => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), _proxy.Credentials), - ProxyProperty.Port => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), _proxy.Credentials), - ProxyProperty.UserName => (_proxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)), - ProxyProperty.Password => (_proxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)), + ProxyProperty.Server => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), WebProxy.Credentials), + ProxyProperty.Port => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), WebProxy.Credentials), + ProxyProperty.UserName => (WebProxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)), + ProxyProperty.Password => (WebProxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)), _ => throw new ArgumentOutOfRangeException() }; } From 0c97db04d4b89d345ddb7908c5a6d361c11c0ee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 17:50:56 +0800 Subject: [PATCH 13/17] 1. Change Get method Name to GetAsync 2. Manually replace "#" with "%23" to solve the similar issue in Explorer plugin 3. Add GetAsync method with Uri as argument 4. Remove unused encoding argument 5. Change exception type for WebSearch Plguin 6. Update Comment --- Flow.Launcher.Core/Updater.cs | 2 +- Flow.Launcher.Infrastructure/Http/Http.cs | 25 +++++++++++++++---- .../SuggestionSources/Baidu.cs | 5 ++-- .../SuggestionSources/Google.cs | 6 ++--- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index d8bc2b6dc32..46fb6d97747 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -133,7 +133,7 @@ private async Task GitHubUpdateManager(string repository) var uri = new Uri(repository); var api = $"https://api.github.com/repos{uri.AbsolutePath}/releases"; - var json = await Http.Get(api); + var json = await Http.GetAsync(api); var releases = JsonConvert.DeserializeObject>(json); var latest = releases.Where(r => !r.Prerelease).OrderByDescending(r => r.PublishedAt).First(); diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 3d056b28b90..8e2832690e4 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -89,13 +89,23 @@ public static async Task Download([NotNull] string url, [NotNull] string filePat } } - public static async Task Get([NotNull] string url, string encoding = "UTF-8") + /// + /// Asynchrously get the result as string from url. + /// When supposing the result is long and large, try using GetStreamAsync to avoid reading as string + /// + /// + /// + public static Task GetAsync([NotNull] string url) { Log.Debug($"|Http.Get|Url <{url}>"); - var response = await client.GetAsync(url); - await using var stream = await response.Content.ReadAsStreamAsync(); - using var reader = new StreamReader(stream, Encoding.GetEncoding(encoding)); - var content = await reader.ReadToEndAsync(); + return GetAsync(new Uri(url.Replace("#", "%23"))); + } + + public static async Task GetAsync([NotNull] Uri url) + { + Log.Debug($"|Http.Get|Url <{url}>"); + using var response = await client.GetAsync(url); + var content = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) { return content; @@ -107,6 +117,11 @@ public static async Task Get([NotNull] string url, string encoding = "UT } } + /// + /// Asynchrously get the result as stream from url. + /// + /// + /// public static async Task GetStreamAsync([NotNull] string url) { Log.Debug($"|Http.Get|Url <{url}>"); diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs index 57db223bcb9..6772acf8256 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs @@ -8,6 +8,7 @@ using Newtonsoft.Json.Linq; using Flow.Launcher.Infrastructure.Http; using Flow.Launcher.Infrastructure.Logger; +using System.Net.Http; namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { @@ -22,9 +23,9 @@ public override async Task> Suggestions(string query) try { const string api = "http://suggestion.baidu.com/su?json=1&wd="; - result = await Http.Get(api + Uri.EscapeUriString(query), "GB2312"); + result = await Http.GetAsync(api + Uri.EscapeUriString(query)).ConfigureAwait(false); } - catch (WebException e) + catch (HttpRequestException e) { Log.Exception("|Baidu.Suggestions|Can't get suggestion from baidu", e); return new List(); diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs index 81878bd8b4a..5b9538091b9 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs @@ -7,6 +7,7 @@ using Newtonsoft.Json.Linq; using Flow.Launcher.Infrastructure.Http; using Flow.Launcher.Infrastructure.Logger; +using System.Net.Http; namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { @@ -18,13 +19,12 @@ public override async Task> Suggestions(string query) try { const string api = "https://www.google.com/complete/search?output=chrome&q="; - result = await Http.Get(api + Uri.EscapeUriString(query)); + result = await Http.GetAsync(api + Uri.EscapeUriString(query)).ConfigureAwait(false); } - catch (WebException e) + catch (HttpRequestException e) { Log.Exception("|Google.Suggestions|Can't get suggestion from google", e); return new List(); - ; } if (string.IsNullOrEmpty(result)) return new List(); JContainer json; From efa4908f37636f3fe6122d241a5821d14a4bf6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 17:54:39 +0800 Subject: [PATCH 14/17] Change usage of Http in Updater.cs and adding ConfigureAwait(false) for await in checking update --- Flow.Launcher.Core/Updater.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 46fb6d97747..05397e906c8 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -29,7 +29,7 @@ public Updater(string gitHubRepository) GitHubRepository = gitHubRepository; } - public async Task UpdateApp(IPublicAPI api , bool silentUpdate = true) + public async Task UpdateApp(IPublicAPI api, bool silentUpdate = true) { UpdateManager updateManager; UpdateInfo newUpdateInfo; @@ -39,7 +39,7 @@ public async Task UpdateApp(IPublicAPI api , bool silentUpdate = true) try { - updateManager = await GitHubUpdateManager(GitHubRepository); + updateManager = await GitHubUpdateManager(GitHubRepository).ConfigureAwait(false); } catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException) { @@ -50,7 +50,7 @@ public async Task UpdateApp(IPublicAPI api , bool silentUpdate = true) try { // UpdateApp CheckForUpdate will return value only if the app is squirrel installed - newUpdateInfo = await updateManager.CheckForUpdate().NonNull(); + newUpdateInfo = await updateManager.CheckForUpdate().NonNull().ConfigureAwait(false); } catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException) { @@ -85,8 +85,8 @@ public async Task UpdateApp(IPublicAPI api , bool silentUpdate = true) updateManager.Dispose(); return; } - - await updateManager.ApplyReleases(newUpdateInfo); + + await updateManager.ApplyReleases(newUpdateInfo).ConfigureAwait(false); if (DataLocation.PortableDataLocationInUse()) { @@ -98,11 +98,11 @@ public async Task UpdateApp(IPublicAPI api , bool silentUpdate = true) } else { - await updateManager.CreateUninstallerRegistryEntry(); + await updateManager.CreateUninstallerRegistryEntry().ConfigureAwait(false); } var newVersionTips = NewVersinoTips(newReleaseVersion.ToString()); - + Log.Info($"|Updater.UpdateApp|Update success:{newVersionTips}"); // always dispose UpdateManager @@ -133,9 +133,9 @@ private async Task GitHubUpdateManager(string repository) var uri = new Uri(repository); var api = $"https://api.github.com/repos{uri.AbsolutePath}/releases"; - var json = await Http.GetAsync(api); + var jsonStream = await Http.GetStreamAsync(api).ConfigureAwait(false); - var releases = JsonConvert.DeserializeObject>(json); + var releases = await System.Text.Json.JsonSerializer.DeserializeAsync>(jsonStream).ConfigureAwait(false); var latest = releases.Where(r => !r.Prerelease).OrderByDescending(r => r.PublishedAt).First(); var latestUrl = latest.HtmlUrl.Replace("/tag/", "/download/"); From d4f94c66acfba5dddf0110b857519feed03eb99c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 18:33:53 +0800 Subject: [PATCH 15/17] Make InstallOrUpdate to async --- Flow.Launcher.Core/Updater.cs | 8 ++++---- Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs | 2 +- .../Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 7 +++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 05397e906c8..1e4b0453c22 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -8,7 +8,6 @@ using System.Windows; using JetBrains.Annotations; using Squirrel; -using Newtonsoft.Json; using Flow.Launcher.Core.Resource; using Flow.Launcher.Plugin.SharedCommands; using Flow.Launcher.Infrastructure; @@ -17,6 +16,7 @@ using System.IO; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; +using System.Text.Json.Serialization; namespace Flow.Launcher.Core { @@ -117,13 +117,13 @@ public async Task UpdateApp(IPublicAPI api, bool silentUpdate = true) [UsedImplicitly] private class GithubRelease { - [JsonProperty("prerelease")] + [JsonPropertyName("prerelease")] public bool Prerelease { get; [UsedImplicitly] set; } - [JsonProperty("published_at")] + [JsonPropertyName("published_at")] public DateTime PublishedAt { get; [UsedImplicitly] set; } - [JsonProperty("html_url")] + [JsonPropertyName("html_url")] public string HtmlUrl { get; [UsedImplicitly] set; } } diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index 716a424ff1b..d700b9dfd27 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -22,7 +22,7 @@ public class Main : ISettingProvider, IPlugin, ISavable, IContextMenu, IPluginI1 internal PluginsManager pluginManager; - private DateTime lastUpdateTime; + private DateTime lastUpdateTime = DateTime.MinValue; public Control CreateSettingPanel() { diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 9635648d480..428610f43b2 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -87,7 +87,7 @@ internal List GetDefaultHotKeys() }; } - internal void InstallOrUpdate(UserPlugin plugin) + internal async Task InstallOrUpdate(UserPlugin plugin) { if (PluginExists(plugin.ID)) { @@ -127,7 +127,7 @@ internal void InstallOrUpdate(UserPlugin plugin) Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), Context.API.GetTranslation("plugin_pluginsmanager_please_wait")); - Http.Download(plugin.UrlDownload, filePath); + await Http.Download(plugin.UrlDownload, filePath).ConfigureAwait(false); Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), Context.API.GetTranslation("plugin_pluginsmanager_download_success")); @@ -264,8 +264,7 @@ internal List RequestInstallOrUpdate(string searchName) Action = e => { Application.Current.MainWindow.Hide(); - InstallOrUpdate(x); - + _ = InstallOrUpdate(x); // No need to wait return ShouldHideWindow; }, ContextData = x From d0743f627668fa5bbd55a3daef37f82064fc3a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 18:48:00 +0800 Subject: [PATCH 16/17] Await Http.Download in Update method --- .../PluginsManager.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 428610f43b2..f12112382ef 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -140,11 +140,8 @@ internal async Task InstallOrUpdate(UserPlugin plugin) Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "PluginDownload"); } - Application.Current.Dispatcher.Invoke(() => - { - Install(plugin, filePath); - Context.API.RestartApp(); - }); + Install(plugin, filePath); + Context.API.RestartApp(); } internal List RequestUpdate(string search) @@ -211,10 +208,14 @@ on existingPlugin.Metadata.ID equals pluginFromManifest.ID var downloadToFilePath = Path.Combine(DataLocation.PluginsDirectory, $"{x.Name}-{x.NewVersion}.zip"); - Http.Download(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath); - Install(x.PluginNewUserPlugin, downloadToFilePath); - Context.API.RestartApp(); + Task.Run(async delegate + { + await Http.Download(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath).ConfigureAwait(false); + Install(x.PluginNewUserPlugin, downloadToFilePath); + + Context.API.RestartApp(); + }); return true; } From c485578cff927a1714344c0eca1ab82870673fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 18:48:55 +0800 Subject: [PATCH 17/17] Use CompareTo to check update for InstallOrUpdate method --- Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index f12112382ef..ac15618ca76 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -92,7 +92,7 @@ internal async Task InstallOrUpdate(UserPlugin plugin) if (PluginExists(plugin.ID)) { if (Context.API.GetAllPlugins() - .Any(x => x.Metadata.ID == plugin.ID && x.Metadata.Version != plugin.Version)) + .Any(x => x.Metadata.ID == plugin.ID && x.Metadata.Version.CompareTo(plugin.Version) < 0)) { if (MessageBox.Show(Context.API.GetTranslation("plugin_pluginsmanager_update_exists"), Context.API.GetTranslation("plugin_pluginsmanager_update_title"),