Merge pull request #178 from taooceros/UpdateHttpMaster

Move Old HttpWebRequest to HttpClient Instance
This commit is contained in:
Jeremy Wu 2020-12-29 22:11:35 +11:00 committed by GitHub
commit 58d281db7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 199 additions and 87 deletions

View file

@ -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);

View file

@ -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();
}
}
}

View file

@ -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);
}
}
}

View file

@ -22,7 +22,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
internal PluginsManager pluginManager;
private DateTime lastUpdateTime;
private DateTime lastUpdateTime = DateTime.MinValue;
public Control CreateSettingPanel()
{

View file

@ -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>();
}
}
}
}
}

View file

@ -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

View file

@ -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>();

View file

@ -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;