diff --git a/Compression.BSA/Compression.BSA.csproj b/Compression.BSA/Compression.BSA.csproj index 1e860870..1836fee8 100644 --- a/Compression.BSA/Compression.BSA.csproj +++ b/Compression.BSA/Compression.BSA.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + netcoreapp3.1 true x64 win10-x64 diff --git a/Wabbajack.Common/Http/Client.cs b/Wabbajack.Common/Http/Client.cs new file mode 100644 index 00000000..19f678dd --- /dev/null +++ b/Wabbajack.Common/Http/Client.cs @@ -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 Cookies = new List(); + public async Task 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 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 SendStringAsync(HttpRequestMessage request) + { + var result = await SendAsync(request); + return await result.Content.ReadAsStringAsync(); + } + + + public async Task 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; + + } + + } + } +} diff --git a/Wabbajack.Common/Http/ClientFactory.cs b/Wabbajack.Common/Http/ClientFactory.cs new file mode 100644 index 00000000..6e2aa00a --- /dev/null +++ b/Wabbajack.Common/Http/ClientFactory.cs @@ -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); + } + } +} diff --git a/Wabbajack.Common/Wabbajack.Common.csproj b/Wabbajack.Common/Wabbajack.Common.csproj index 8498ea3a..45633134 100644 --- a/Wabbajack.Common/Wabbajack.Common.csproj +++ b/Wabbajack.Common/Wabbajack.Common.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + netcoreapp3.1 x64 win10-x64 @@ -39,6 +39,7 @@ + diff --git a/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs b/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs index 0ac94906..601b653f 100644 --- a/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs +++ b/Wabbajack.Lib/Downloaders/AbstractNeedsLoginDownloader.cs @@ -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; /// /// 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 GetAuthedClient() + public async Task GetAuthedClient() { Helpers.Cookie[] cookies; try diff --git a/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs b/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs index 06afd874..bf8086e3 100644 --- a/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs +++ b/Wabbajack.Lib/Downloaders/GoogleDriveDownloader.cs @@ -53,7 +53,7 @@ namespace Wabbajack.Lib.Downloaders private async Task 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); diff --git a/Wabbajack.Lib/Downloaders/HTTPDownloader.cs b/Wabbajack.Lib/Downloaders/HTTPDownloader.cs index 860a6848..63e92e0c 100644 --- a/Wabbajack.Lib/Downloaders/HTTPDownloader.cs +++ b/Wabbajack.Lib/Downloaders/HTTPDownloader.cs @@ -61,7 +61,7 @@ namespace Wabbajack.Lib.Downloaders public List 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; diff --git a/Wabbajack.Lib/Downloaders/MediaFireDownloader.cs b/Wabbajack.Lib/Downloaders/MediaFireDownloader.cs index 65b341d8..08d3f898 100644 --- a/Wabbajack.Lib/Downloaders/MediaFireDownloader.cs +++ b/Wabbajack.Lib/Downloaders/MediaFireDownloader.cs @@ -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 }; } diff --git a/Wabbajack.Lib/LibCefHelpers/Init.cs b/Wabbajack.Lib/LibCefHelpers/Init.cs index f411d74a..e3b0729a 100644 --- a/Wabbajack.Lib/LibCefHelpers/Init.cs +++ b/Wabbajack.Lib/LibCefHelpers/Init.cs @@ -16,13 +16,15 @@ namespace Wabbajack.Lib.LibCefHelpers { public static class Helpers { - public static HttpClient GetClient(IEnumerable cookies, string referer) + public static Common.Http.Client GetClient(IEnumerable 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 cookies) diff --git a/Wabbajack.Lib/NexusApi/NexusApi.cs b/Wabbajack.Lib/NexusApi/NexusApi.cs index 6dcf63b2..6357b36e 100644 --- a/Wabbajack.Lib/NexusApi/NexusApi.cs +++ b/Wabbajack.Lib/NexusApi/NexusApi.cs @@ -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(url); } - public async Task 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 { { "version", mod.Version } }); - - using (var stream = await HttpClient.PostStream(url, content)) - { - return stream.FromJSON(); - } - } - private class DownloadLink { public string URI { get; set; } diff --git a/Wabbajack.Lib/StatusMessages/ManuallyDownloadFile.cs b/Wabbajack.Lib/StatusMessages/ManuallyDownloadFile.cs index 0bef7492..a782e089 100644 --- a/Wabbajack.Lib/StatusMessages/ManuallyDownloadFile.cs +++ b/Wabbajack.Lib/StatusMessages/ManuallyDownloadFile.cs @@ -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)); } diff --git a/Wabbajack.Lib/Wabbajack.Lib.csproj b/Wabbajack.Lib/Wabbajack.Lib.csproj index 06e5a53a..62b329b5 100644 --- a/Wabbajack.Lib/Wabbajack.Lib.csproj +++ b/Wabbajack.Lib/Wabbajack.Lib.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + netcoreapp3.1 x64 win10-x64 diff --git a/Wabbajack.VirtualFileSystem/Wabbajack.VirtualFileSystem.csproj b/Wabbajack.VirtualFileSystem/Wabbajack.VirtualFileSystem.csproj index 47e68e3f..a2ec35cc 100644 --- a/Wabbajack.VirtualFileSystem/Wabbajack.VirtualFileSystem.csproj +++ b/Wabbajack.VirtualFileSystem/Wabbajack.VirtualFileSystem.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + netcoreapp3.1 x64 win10-x64 diff --git a/Wabbajack.sln b/Wabbajack.sln index d0b9081c..e4766ed6 100644 --- a/Wabbajack.sln +++ b/Wabbajack.sln @@ -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