Swap HttpClient over to SocketsHttpHandler

This commit is contained in:
Timothy Baldridge 2020-02-14 15:23:27 -07:00
parent b77db18bfa
commit 8d13a4c455
14 changed files with 124 additions and 48 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Platforms>x64</Platforms>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace Wabbajack.Common.Http
{
public class Client
{
public List<(string, string)> Headers => new List<(string, string)>();
public List<Cookie> Cookies = new List<Cookie>();
public async Task<HttpResponseMessage> GetAsync(string url, HttpCompletionOption responseHeadersRead = HttpCompletionOption.ResponseContentRead)
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
foreach (var (k, v) in Headers)
request.Headers.Add(k, v);
return await SendAsync(request, responseHeadersRead);
}
public async Task<string> GetStringAsync(string url)
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
foreach (var (k, v) in Headers)
request.Headers.Add(k, v);
if (Cookies.Count > 0)
Cookies.ForEach(c => ClientFactory.Cookies.Add(c));
return await SendStringAsync(request);
}
private async Task<string> SendStringAsync(HttpRequestMessage request)
{
var result = await SendAsync(request);
return await result.Content.ReadAsStringAsync();
}
public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage msg, HttpCompletionOption responseHeadersRead = HttpCompletionOption.ResponseContentRead)
{
int retries = 0;
TOP:
try
{
var response = await ClientFactory.Client.SendAsync(msg, responseHeadersRead);
return response;
}
catch (Exception)
{
if (retries > Consts.MaxHTTPRetries) throw;
retries++;
Utils.Log($"Http Connect error to {msg.RequestUri} retry {retries}");
await Task.Delay(100 * retries);
goto TOP;
}
}
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Net;
using SysHttp = System.Net.Http;
namespace Wabbajack.Common.Http
{
public static class ClientFactory
{
private static SysHttp.SocketsHttpHandler _socketsHandler { get; }
internal static SysHttp.HttpClient Client { get; }
internal static CookieContainer Cookies { get; }
static ClientFactory()
{
Cookies = new CookieContainer();
_socketsHandler = new SysHttp.SocketsHttpHandler
{
CookieContainer = Cookies,
MaxConnectionsPerServer = 8,
PooledConnectionLifetime = TimeSpan.FromSeconds(2),
PooledConnectionIdleTimeout = TimeSpan.FromSeconds(2)
};
Client = new SysHttp.HttpClient(_socketsHandler);
}
}
}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Platforms>x64</Platforms>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
@ -39,6 +39,7 @@
<PackageReference Include="ReactiveUI" Version="11.1.23" />
<PackageReference Include="SharpZipLib" Version="1.2.0" />
<PackageReference Include="System.Data.HashFunction.xxHash" Version="2.0.0" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.7.0" />
<PackageReference Include="System.Security.Principal.Windows" Version="4.7.0" />
<PackageReference Include="YamlDotNet" Version="8.1.0" />

View File

@ -21,7 +21,7 @@ namespace Wabbajack.Lib.Downloaders
private readonly string _encryptedKeyName;
private readonly string _cookieDomain;
private readonly string _cookieName;
internal HttpClient AuthedClient;
internal Common.Http.Client AuthedClient;
/// <summary>
/// Sets up all the login facilites needed for a INeedsLogin downloader based on having the user log
@ -81,7 +81,7 @@ namespace Wabbajack.Lib.Downloaders
return cookies;
}
public async Task<HttpClient> GetAuthedClient()
public async Task<Common.Http.Client> GetAuthedClient()
{
Helpers.Cookie[] cookies;
try

View File

@ -53,7 +53,7 @@ namespace Wabbajack.Lib.Downloaders
private async Task<HTTPDownloader.State> ToHttpState()
{
var initialURL = $"https://drive.google.com/uc?id={Id}&export=download";
var client = new HttpClient();
var client = new Common.Http.Client();
var response = await client.GetAsync(initialURL);
if (!response.IsSuccessStatusCode)
throw new HttpException((int)response.StatusCode, response.ReasonPhrase);

View File

@ -61,7 +61,7 @@ namespace Wabbajack.Lib.Downloaders
public List<string> Headers { get; set; }
[Exclude]
public HttpClient Client { get; set; }
public Common.Http.Client Client { get; set; }
public override object[] PrimaryKey { get => new object[] {Url};}
@ -86,8 +86,8 @@ namespace Wabbajack.Lib.Downloaders
using (var fs = download ? File.Open(destination, FileMode.Create) : null)
{
var client = Client ?? new HttpClient();
client.DefaultRequestHeaders.Add("User-Agent", Consts.UserAgent);
var client = Client ?? new Common.Http.Client();
client.Headers.Add(("User-Agent", Consts.UserAgent));
if (Headers != null)
foreach (var header in Headers)
@ -95,7 +95,7 @@ namespace Wabbajack.Lib.Downloaders
var idx = header.IndexOf(':');
var k = header.Substring(0, idx);
var v = header.Substring(idx + 1);
client.DefaultRequestHeaders.Add(k, v);
client.Headers.Add((k, v));
}
long totalRead = 0;

View File

@ -53,7 +53,7 @@ namespace Wabbajack.Lib.Downloaders
if (newURL == null || !newURL.StartsWith("http")) return null;
return new HTTPDownloader.State()
{
Client = new HttpClient(),
Client = new Common.Http.Client(),
Url = newURL
};
}

View File

@ -16,13 +16,15 @@ namespace Wabbajack.Lib.LibCefHelpers
{
public static class Helpers
{
public static HttpClient GetClient(IEnumerable<Cookie> cookies, string referer)
public static Common.Http.Client GetClient(IEnumerable<Cookie> cookies, string referer)
{
throw new NotImplementedException("tt");
/*
var container = ToCookieContainer(cookies);
var handler = new HttpClientHandler { CookieContainer = container };
var client = new HttpClient(handler);
client.DefaultRequestHeaders.Referrer = new Uri(referer);
return client;
return client;*/
}
private static CookieContainer ToCookieContainer(IEnumerable<Cookie> cookies)

View File

@ -23,10 +23,8 @@ namespace Wabbajack.Lib.NexusApi
{
private static readonly string API_KEY_CACHE_FILE = "nexus.key_cache";
private static string _additionalEntropy = "vtP2HF6ezg";
private static object _diskLock = new object();
public HttpClient HttpClient { get; } = new HttpClient(new HttpClientHandler {MaxConnectionsPerServer = Consts.MaxConnectionsPerServer}) {Timeout = TimeSpan.FromMinutes(1), DefaultRequestHeaders = {ConnectionClose = true}};
public Common.Http.Client HttpClient { get; } = new Common.Http.Client();
#region Authentication
@ -202,14 +200,13 @@ namespace Wabbajack.Lib.NexusApi
{
ApiKey = apiKey;
HttpClient.BaseAddress = new Uri("https://api.nexusmods.com");
// set default headers for all requests to the Nexus API
var headers = HttpClient.DefaultRequestHeaders;
headers.Add("User-Agent", Consts.UserAgent);
headers.Add("apikey", ApiKey);
headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
headers.Add("Application-Name", Consts.AppName);
headers.Add("Application-Version", $"{Assembly.GetEntryAssembly()?.GetName()?.Version ?? new Version(0, 1)}");
var headers = HttpClient.Headers;
headers.Add(("User-Agent", Consts.UserAgent));
headers.Add(("apikey", ApiKey));
headers.Add(("Accept", "application/json"));
headers.Add(("Application-Name", Consts.AppName));
headers.Add(("Application-Version", $"{Assembly.GetEntryAssembly()?.GetName()?.Version ?? new Version(0, 1)}"));
if (!Directory.Exists(Consts.NexusCacheDirectory))
Directory.CreateDirectory(Consts.NexusCacheDirectory);
@ -329,19 +326,6 @@ namespace Wabbajack.Lib.NexusApi
return await GetCached<ModInfo>(url);
}
public async Task<EndorsementResponse> EndorseMod(NexusDownloader.State mod)
{
Utils.Status($"Endorsing ${mod.GameName} - ${mod.ModID}");
var url = $"https://api.nexusmods.com/v1/games/{ConvertGameName(mod.GameName)}/mods/{mod.ModID}/endorse.json";
var content = new FormUrlEncodedContent(new Dictionary<string, string> { { "version", mod.Version } });
using (var stream = await HttpClient.PostStream(url, content))
{
return stream.FromJSON<EndorsementResponse>();
}
}
private class DownloadLink
{
public string URI { get; set; }

View File

@ -12,8 +12,8 @@ namespace Wabbajack.Lib
public override string ShortDescription { get; }
public override string ExtendedDescription { get; }
private TaskCompletionSource<(Uri, HttpClient)> _tcs = new TaskCompletionSource<(Uri, HttpClient)>();
public Task<(Uri, HttpClient)> Task => _tcs.Task;
private TaskCompletionSource<(Uri, Common.Http.Client)> _tcs = new TaskCompletionSource<(Uri, Common.Http.Client)>();
public Task<(Uri, Common.Http.Client)> Task => _tcs.Task;
private ManuallyDownloadFile(ManualDownloader.State state)
{
@ -30,7 +30,7 @@ namespace Wabbajack.Lib
_tcs.SetCanceled();
}
public void Resume(Uri s, HttpClient client)
public void Resume(Uri s, Common.Http.Client client)
{
_tcs.SetResult((s, client));
}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Platforms>x64</Platforms>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Platforms>x64</Platforms>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
</PropertyGroup>

View File

@ -38,7 +38,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wabbajack.Test", "Wabbajack
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wabbajack.CLI", "Wabbajack.CLI\Wabbajack.CLI.csproj", "{685D8BB1-D178-4D2C-85C7-C54A36FB7454}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wabbajack.Launcher", "Wabbajack.Launcher\Wabbajack.Launcher.csproj", "{D6856DBF-C959-4867-A8A8-343DA2D2715E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wabbajack.Launcher", "Wabbajack.Launcher\Wabbajack.Launcher.csproj", "{D6856DBF-C959-4867-A8A8-343DA2D2715E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -84,12 +84,14 @@ Global
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Release|Any CPU.ActiveCfg = Release|x64
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Release|x64.ActiveCfg = Release|x64
{37E4D421-8FD3-4D57-8F3A-7A511D6ED5C5}.Release|x64.Build.0 = Release|x64
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|Any CPU.ActiveCfg = Debug|x64
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|x64.ActiveCfg = Debug|x64
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|x64.Build.0 = Debug|x64
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Release|Any CPU.ActiveCfg = Release|x64
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Release|x64.ActiveCfg = Release|x64
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Release|x64.Build.0 = Release|x64
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|x64.ActiveCfg = Debug|Any CPU
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Debug|x64.Build.0 = Debug|Any CPU
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Release|Any CPU.Build.0 = Release|Any CPU
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Release|x64.ActiveCfg = Release|Any CPU
{DE18D89E-39C5-48FD-8E42-16235E3C4593}.Release|x64.Build.0 = Release|Any CPU
{6ED08CFB-B879-4B55-8741-663A4A3491CE}.Debug|Any CPU.ActiveCfg = Debug|x64
{6ED08CFB-B879-4B55-8741-663A4A3491CE}.Debug|x64.ActiveCfg = Debug|x64
{6ED08CFB-B879-4B55-8741-663A4A3491CE}.Debug|x64.Build.0 = Debug|x64