From 785b43781a474c665db4cd85da331bda4725a44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C3=B6ls?= <6608231+Abrynos@users.noreply.github.com> Date: Wed, 27 Oct 2021 13:15:56 +0200 Subject: [PATCH] Support lol-US locale for IPC requests (#2435) * Support lol-US locale for IPC requests * Support sr-CS as well * Apply feedback * Apply feedback and Rider cleanup * Less allocations make everyone happy * Apply feedback * Explain why we're doing this stupidity * Uppercase Windows/Linux compat fix * Go back to earlier version --- ArchiSteamFarm/Core/AprilFools.cs | 2 +- .../IPC/Integration/LocalizationMiddleware.cs | 84 +++++++++++++++++++ ArchiSteamFarm/IPC/Startup.cs | 6 +- ArchiSteamFarm/SharedInfo.cs | 1 + 4 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 ArchiSteamFarm/IPC/Integration/LocalizationMiddleware.cs diff --git a/ArchiSteamFarm/Core/AprilFools.cs b/ArchiSteamFarm/Core/AprilFools.cs index 18a666dcd..fab61c4cf 100644 --- a/ArchiSteamFarm/Core/AprilFools.cs +++ b/ArchiSteamFarm/Core/AprilFools.cs @@ -37,7 +37,7 @@ namespace ArchiSteamFarm.Core { if ((now.Month == 4) && (now.Day == 1)) { try { - CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture("qps-Ploc"); + CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture(SharedInfo.LolcatCultureName); } catch (Exception e) { ASF.ArchiLogger.LogGenericDebuggingException(e); diff --git a/ArchiSteamFarm/IPC/Integration/LocalizationMiddleware.cs b/ArchiSteamFarm/IPC/Integration/LocalizationMiddleware.cs new file mode 100644 index 000000000..ef4e7b945 --- /dev/null +++ b/ArchiSteamFarm/IPC/Integration/LocalizationMiddleware.cs @@ -0,0 +1,84 @@ +// _ _ _ ____ _ _____ +// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___ +// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \ +// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | | +// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_| +// | +// Copyright 2015-2021 Ɓukasz "JustArchi" Domeradzki +// Contact: JustArchi@JustArchi.net +// | +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// | +// http://www.apache.org/licenses/LICENSE-2.0 +// | +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Headers; +using Microsoft.Extensions.Primitives; +using Microsoft.Net.Http.Headers; + +namespace ArchiSteamFarm.IPC.Integration { + [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] + internal sealed class LocalizationMiddleware { + internal static readonly ImmutableDictionary CultureConversions = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "lol-US", SharedInfo.LolcatCultureName }, { "sr-CS", "sr-Latn" } }.ToImmutableDictionary(); + + private readonly RequestDelegate Next; + + public LocalizationMiddleware(RequestDelegate next) => Next = next ?? throw new ArgumentNullException(nameof(next)); + + [UsedImplicitly] + public async Task InvokeAsync(HttpContext context) { + if (context == null) { + throw new ArgumentNullException(nameof(context)); + } + + RequestHeaders headers = context.Request.GetTypedHeaders(); + + IList? acceptLanguageHeader = headers.AcceptLanguage; + + if ((acceptLanguageHeader == null) || (acceptLanguageHeader.Count == 0)) { + await Next(context).ConfigureAwait(false); + + return; + } + + bool valuesChanged = false; + + for (int i = 0; i < acceptLanguageHeader.Count; i++) { + StringSegment language = acceptLanguageHeader[i].Value; + + if (!language.HasValue || string.IsNullOrEmpty(language.Value)) { + continue; + } + + if (!CultureConversions.TryGetValue(language.Value, out string? replacement) || string.IsNullOrEmpty(replacement)) { + continue; + } + + acceptLanguageHeader[i] = StringWithQualityHeaderValue.Parse(replacement); + valuesChanged = true; + } + + if (valuesChanged) { + // The getter returns a temporary collection; To make sure our changes are persisted, we need to assign it back + headers.AcceptLanguage = acceptLanguageHeader; + } + + await Next(context).ConfigureAwait(false); + } + } +} diff --git a/ArchiSteamFarm/IPC/Startup.cs b/ArchiSteamFarm/IPC/Startup.cs index 81c75bda4..493356a37 100644 --- a/ArchiSteamFarm/IPC/Startup.cs +++ b/ArchiSteamFarm/IPC/Startup.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Linq; using System.Net; using System.Reflection; using ArchiSteamFarm.Core; @@ -140,6 +141,7 @@ namespace ArchiSteamFarm.IPC { } ); + app.UseMiddleware(); app.UseRequestLocalization(); // Use routing for our API controllers, this should be called once we're done with all the static files mess @@ -222,7 +224,9 @@ namespace ArchiSteamFarm.IPC { #endif static options => { // We do not set the DefaultRequestCulture here, because it will default to Thread.CurrentThread.CurrentCulture in this case, which is set when loading GlobalConfig - options.SupportedUICultures = options.SupportedCultures = CultureInfo.GetCultures(CultureTypes.AllCultures); + + List supportedCultures = CultureInfo.GetCultures(CultureTypes.AllCultures).Append(CultureInfo.CreateSpecificCulture(SharedInfo.LolcatCultureName)).ToList(); + options.SupportedUICultures = options.SupportedCultures = supportedCultures; // The default checks the URI and cookies and only then for headers; ASFs IPC does not use either of the higher priority mechanisms anywhere else and we don't want to start here. options.RequestCultureProviders = new List { new AcceptLanguageHeaderRequestCultureProvider() }; diff --git a/ArchiSteamFarm/SharedInfo.cs b/ArchiSteamFarm/SharedInfo.cs index 7253184f7..57a17114a 100644 --- a/ArchiSteamFarm/SharedInfo.cs +++ b/ArchiSteamFarm/SharedInfo.cs @@ -57,6 +57,7 @@ namespace ArchiSteamFarm { internal const string LicenseName = "Apache 2.0"; internal const string LicenseURL = "https://www.apache.org/licenses/LICENSE-2.0"; internal const string LogFile = "log.txt"; + internal const string LolcatCultureName = "qps-Ploc"; internal const string MobileAuthenticatorExtension = ".maFile"; internal const string PluginsDirectory = "plugins"; internal const string ProjectURL = "https://github.com/" + GithubRepo;