mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge pull request #178 from taooceros/UpdateHttpMaster
Move Old HttpWebRequest to HttpClient Instance
This commit is contained in:
commit
58d281db7a
8 changed files with 199 additions and 87 deletions
|
|
@ -8,7 +8,6 @@ using System.Threading.Tasks;
|
|||
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 Flow.Launcher.Infrastructure.Logger;
|
|||
using System.IO;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Flow.Launcher.Core
|
||||
{
|
||||
|
|
@ -29,7 +29,7 @@ namespace Flow.Launcher.Core
|
|||
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 @@ namespace Flow.Launcher.Core
|
|||
|
||||
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 @@ namespace Flow.Launcher.Core
|
|||
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 @@ namespace Flow.Launcher.Core
|
|||
updateManager.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
await updateManager.ApplyReleases(newUpdateInfo);
|
||||
|
||||
await updateManager.ApplyReleases(newUpdateInfo).ConfigureAwait(false);
|
||||
|
||||
if (DataLocation.PortableDataLocationInUse())
|
||||
{
|
||||
|
|
@ -98,11 +98,11 @@ namespace Flow.Launcher.Core
|
|||
}
|
||||
else
|
||||
{
|
||||
await updateManager.CreateUninstallerRegistryEntry();
|
||||
await updateManager.CreateUninstallerRegistryEntry().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var newVersionTips = NewVersinoTips(newReleaseVersion.ToString());
|
||||
|
||||
|
||||
Log.Info($"|Updater.UpdateApp|Update success:{newVersionTips}");
|
||||
|
||||
// always dispose UpdateManager
|
||||
|
|
@ -117,13 +117,13 @@ namespace Flow.Launcher.Core
|
|||
[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; }
|
||||
}
|
||||
|
||||
|
|
@ -133,13 +133,13 @@ namespace Flow.Launcher.Core
|
|||
var uri = new Uri(repository);
|
||||
var api = $"https://api.github.com/repos{uri.AbsolutePath}/releases";
|
||||
|
||||
var json = await Http.Get(api);
|
||||
var jsonStream = await Http.GetStreamAsync(api).ConfigureAwait(false);
|
||||
|
||||
var releases = JsonConvert.DeserializeObject<List<GithubRelease>>(json);
|
||||
var releases = await System.Text.Json.JsonSerializer.DeserializeAsync<List<GithubRelease>>(jsonStream).ConfigureAwait(false);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ using System.Threading.Tasks;
|
|||
using JetBrains.Annotations;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure.Http
|
||||
{
|
||||
|
|
@ -13,6 +15,14 @@ namespace Flow.Launcher.Infrastructure.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,71 +30,103 @@ namespace Flow.Launcher.Infrastructure.Http
|
|||
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls
|
||||
| SecurityProtocolType.Tls11
|
||||
| SecurityProtocolType.Tls12;
|
||||
|
||||
client = new HttpClient(socketsHttpHandler, false);
|
||||
client.DefaultRequestHeaders.Add("User-Agent", UserAgent);
|
||||
}
|
||||
|
||||
public static HttpProxy Proxy { private get; set; }
|
||||
public static IWebProxy WebProxy()
|
||||
private static HttpProxy proxy;
|
||||
|
||||
public static HttpProxy Proxy
|
||||
{
|
||||
if (Proxy != null && Proxy.Enabled && !string.IsNullOrEmpty(Proxy.Server))
|
||||
private get { return proxy; }
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(Proxy.UserName) || string.IsNullOrEmpty(Proxy.Password))
|
||||
proxy = value;
|
||||
proxy.PropertyChanged += UpdateProxy;
|
||||
}
|
||||
}
|
||||
|
||||
public static WebProxy WebProxy { get; } = new WebProxy();
|
||||
|
||||
/// <summary>
|
||||
/// Update the Address of the Proxy to modify the client Proxy
|
||||
/// </summary>
|
||||
public static void UpdateProxy(ProxyProperty property)
|
||||
{
|
||||
(WebProxy.Address, WebProxy.Credentials) = property switch
|
||||
{
|
||||
ProxyProperty.Enabled => Proxy.Enabled switch
|
||||
{
|
||||
var webProxy = new WebProxy(Proxy.Server, Proxy.Port);
|
||||
return webProxy;
|
||||
}
|
||||
else
|
||||
{
|
||||
var webProxy = new WebProxy(Proxy.Server, Proxy.Port)
|
||||
true => Proxy.UserName switch
|
||||
{
|
||||
Credentials = new NetworkCredential(Proxy.UserName, Proxy.Password)
|
||||
};
|
||||
return webProxy;
|
||||
}
|
||||
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}"), 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()
|
||||
};
|
||||
}
|
||||
|
||||
public static async Task Download([NotNull] string url, [NotNull] string filePath)
|
||||
{
|
||||
using var response = await client.GetAsync(url);
|
||||
if (response.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
await using var fileStream = new FileStream(filePath, FileMode.CreateNew);
|
||||
await response.Content.CopyToAsync(fileStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
return WebRequest.GetSystemWebProxy();
|
||||
throw new HttpRequestException($"Error code <{response.StatusCode}> returned from <{url}>");
|
||||
}
|
||||
}
|
||||
|
||||
public static void Download([NotNull] string url, [NotNull] string filePath)
|
||||
{
|
||||
var client = new WebClient { Proxy = WebProxy() };
|
||||
client.Headers.Add("user-agent", UserAgent);
|
||||
client.DownloadFile(url, filePath);
|
||||
}
|
||||
|
||||
public static async Task<string> Get([NotNull] string url, string encoding = "UTF-8")
|
||||
/// <summary>
|
||||
/// Asynchrously get the result as string from url.
|
||||
/// When supposing the result is long and large, try using GetStreamAsync to avoid reading as string
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
public static Task<string> GetAsync([NotNull] string url)
|
||||
{
|
||||
Log.Debug($"|Http.Get|Url <{url}>");
|
||||
var request = WebRequest.CreateHttp(url);
|
||||
request.Method = "GET";
|
||||
request.Timeout = 6000;
|
||||
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 content = await reader.ReadToEndAsync();
|
||||
if (response.StatusCode != HttpStatusCode.OK)
|
||||
throw new HttpRequestException($"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>");
|
||||
|
||||
return content;
|
||||
return GetAsync(new Uri(url.Replace("#", "%23")));
|
||||
}
|
||||
|
||||
public static async Task<string> 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;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new HttpRequestException(
|
||||
$"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asynchrously get the result as stream from url.
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<Stream> GetStreamAsync([NotNull] string url)
|
||||
{
|
||||
Log.Debug($"|Http.Get|Url <{url}>");
|
||||
var request = WebRequest.CreateHttp(url);
|
||||
request.Method = "GET";
|
||||
request.Timeout = 6000;
|
||||
request.Proxy = WebProxy();
|
||||
request.UserAgent = UserAgent;
|
||||
var response = await request.GetResponseAsync() as HttpWebResponse;
|
||||
response = response.NonNull();
|
||||
return response.GetResponseStream().NonNull();
|
||||
var response = await client.GetAsync(url);
|
||||
return await response.Content.ReadAsStreamAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
|
||||
internal PluginsManager pluginManager;
|
||||
|
||||
private DateTime lastUpdateTime;
|
||||
private DateTime lastUpdateTime = DateTime.MinValue;
|
||||
|
||||
public Control CreateSettingPanel()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models
|
|||
internal class PluginsManifest
|
||||
{
|
||||
internal List<UserPlugin> UserPlugins { get; private set; }
|
||||
|
||||
internal PluginsManifest()
|
||||
{
|
||||
Task.Run(async () => await DownloadManifest()).Wait();
|
||||
|
|
@ -30,7 +31,6 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models
|
|||
|
||||
UserPlugins = new List<UserPlugin>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -87,12 +87,12 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
};
|
||||
}
|
||||
|
||||
internal void InstallOrUpdate(UserPlugin plugin)
|
||||
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"),
|
||||
|
|
@ -127,7 +127,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
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"));
|
||||
|
|
@ -140,11 +140,8 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
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<Result> RequestUpdate(string search)
|
||||
|
|
@ -211,10 +208,14 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
@ -264,8 +265,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
Action = e =>
|
||||
{
|
||||
Application.Current.MainWindow.Hide();
|
||||
InstallOrUpdate(x);
|
||||
|
||||
_ = InstallOrUpdate(x); // No need to wait
|
||||
return ShouldHideWindow;
|
||||
},
|
||||
ContextData = x
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using Newtonsoft.Json;
|
|||
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 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources
|
|||
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<string>();
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using Newtonsoft.Json;
|
|||
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 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources
|
|||
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<string>();
|
||||
;
|
||||
}
|
||||
if (string.IsNullOrEmpty(result)) return new List<string>();
|
||||
JContainer json;
|
||||
|
|
|
|||
Loading…
Reference in a new issue