diff --git a/Application/Application.csproj b/Application/Application.csproj
index 78ebd5fb8..fffa5b9ce 100644
--- a/Application/Application.csproj
+++ b/Application/Application.csproj
@@ -32,11 +32,13 @@
+
+
- false
+ true
true
true
Latest
diff --git a/Application/ApplicationManager.cs b/Application/ApplicationManager.cs
index fe1de1f9b..98e395127 100644
--- a/Application/ApplicationManager.cs
+++ b/Application/ApplicationManager.cs
@@ -581,9 +581,9 @@ namespace IW4MAdmin.Application
throw lastException;
}
- if (successServers != config.Servers.Length)
+ if (successServers != config.Servers.Length && !AppContext.TryGetSwitch("NoConfirmPrompt", out _))
{
- if (!Utilities.PromptBool(Utilities.CurrentLocalization.LocalizationIndex["MANAGER_START_WITH_ERRORS"]))
+ if (!Utilities.CurrentLocalization.LocalizationIndex["MANAGER_START_WITH_ERRORS"].PromptBool())
{
throw lastException;
}
diff --git a/Application/Main.cs b/Application/Main.cs
index 83101a043..41eb9901c 100644
--- a/Application/Main.cs
+++ b/Application/Main.cs
@@ -58,7 +58,7 @@ namespace IW4MAdmin.Application
/// entrypoint of the application
///
///
- public static async Task Main(string[] args)
+ public static async Task Main(bool noConfirm = false, int? maxConcurrentRequests = 25, int? requestQueueLimit = 25)
{
AppDomain.CurrentDomain.SetData("DataDirectory", Utilities.OperatingDirectory);
AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) =>
@@ -73,7 +73,15 @@ namespace IW4MAdmin.Application
// added to be a bit more permissive with plugin references
return AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(asm => asm.FullName?.StartsWith(libraryName) ?? false);
- };
+ };
+
+ if (noConfirm)
+ {
+ AppContext.SetSwitch("NoConfirmPrompt", true);
+ }
+
+ Environment.SetEnvironmentVariable("MaxConcurrentRequests", (maxConcurrentRequests * Environment.ProcessorCount).ToString());
+ Environment.SetEnvironmentVariable("RequestQueueLimit", requestQueueLimit.ToString());
Console.OutputEncoding = Encoding.UTF8;
Console.ForegroundColor = ConsoleColor.Gray;
@@ -86,7 +94,7 @@ namespace IW4MAdmin.Application
Console.WriteLine($" Version {Utilities.GetVersionAsString()}");
Console.WriteLine("=====================================================");
- await LaunchAsync(args);
+ await LaunchAsync();
}
///
@@ -112,13 +120,13 @@ namespace IW4MAdmin.Application
/// task that initializes application and starts the application monitoring and runtime tasks
///
///
- private static async Task LaunchAsync(string[] args)
+ private static async Task LaunchAsync()
{
restart:
ITranslationLookup translationLookup = null;
var logger = BuildDefaultLogger(new ApplicationConfiguration());
Utilities.DefaultLogger = logger;
- logger.LogInformation("Begin IW4MAdmin startup. Version is {Version} {@Args}", Version, args);
+ logger.LogInformation("Begin IW4MAdmin startup. Version is {Version}", Version);
try
{
@@ -426,9 +434,9 @@ namespace IW4MAdmin.Application
commandConfigHandler.BuildAsync().GetAwaiter().GetResult();
var appConfig = appConfigHandler.Configuration();
- var masterUri = /*Utilities.IsDevelopment
+ var masterUri = Utilities.IsDevelopment
? new Uri("http://127.0.0.1:8080")
- : appConfig?.MasterUrl ?? */new ApplicationConfiguration().MasterUrl;
+ : appConfig?.MasterUrl ?? new ApplicationConfiguration().MasterUrl;
var httpClient = new HttpClient
{
BaseAddress = masterUri,
diff --git a/WebfrontCore/Controllers/DynamicFileController.cs b/WebfrontCore/Controllers/DynamicFileController.cs
deleted file mode 100644
index 9b5bbb00a..000000000
--- a/WebfrontCore/Controllers/DynamicFileController.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using Microsoft.AspNetCore.Mvc;
-using SharedLibraryCore;
-using SharedLibraryCore.Interfaces;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace WebfrontCore.Controllers
-{
- [Route("dynamic")]
- public class DynamicFileController : BaseController
- {
- private static readonly IDictionary _fileCache = new Dictionary();
-
- public DynamicFileController(IManager manager) : base(manager)
- {
-
- }
-
- [Route("css/{fileName}")]
- public async Task Css(string fileName)
- {
- if (fileName.EndsWith(".css"))
- {
- if (Utilities.IsDevelopment)
- {
- var path = Path.Join(Utilities.OperatingDirectory, "..", "..", "..", "..", "WebfrontCore", "wwwroot", "css", fileName);
- string cssData = await System.IO.File.ReadAllTextAsync(path);
- cssData = await Manager.MiddlewareActionHandler.Execute(cssData, "custom_css_accent");
- return Content(cssData, "text/css");
- }
-
- if (!_fileCache.ContainsKey(fileName))
- {
-
- string path = $"wwwroot{Path.DirectorySeparatorChar}css{Path.DirectorySeparatorChar}{fileName}";
- string data = await System.IO.File.ReadAllTextAsync(path);
- data = await Manager.MiddlewareActionHandler.Execute(data, "custom_css_accent");
- _fileCache.Add(fileName, data);
- }
-
- return Content(_fileCache[fileName], "text/css");
- }
-
- return StatusCode(400);
- }
- }
-}
diff --git a/WebfrontCore/Middleware/CustomCssAccentMiddlewareAction.cs b/WebfrontCore/Middleware/CustomCssAccentMiddlewareAction.cs
deleted file mode 100644
index cf98a45bd..000000000
--- a/WebfrontCore/Middleware/CustomCssAccentMiddlewareAction.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-using SharedLibraryCore.Interfaces;
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Globalization;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace WebfrontCore.Middleware
-{
- public class CustomCssAccentMiddlewareAction : IMiddlewareAction
- {
- private readonly List ColorReplacements = new List();
-
- private class ColorMap
- {
- public Color Original { get; set; }
- public Color Replacement { get; set; }
- }
-
- public CustomCssAccentMiddlewareAction(string originalPrimaryColor, string originalSecondaryColor, string primaryColor, string secondaryColor)
- {
- primaryColor = string.IsNullOrWhiteSpace(primaryColor) ? originalPrimaryColor : primaryColor;
- secondaryColor = string.IsNullOrWhiteSpace(secondaryColor) ? originalSecondaryColor : secondaryColor;
- try
- {
- ColorReplacements.AddRange(new[]
- {
- new ColorMap()
- {
- Original = Color.FromArgb(Convert.ToInt32(originalPrimaryColor.Substring(1).ToString(), 16)),
- Replacement = Color.FromArgb(Convert.ToInt32(primaryColor.Substring(1).ToString(), 16))
- },
- new ColorMap()
- {
- Original = Color.FromArgb(Convert.ToInt32(originalSecondaryColor.Substring(1).ToString(), 16)),
- Replacement = Color.FromArgb(Convert.ToInt32(secondaryColor.Substring(1).ToString(), 16))
- }
- });
- }
-
- catch (FormatException)
- {
-
- }
- }
-
- public Task Invoke(string original)
- {
- foreach (var color in ColorReplacements)
- {
- foreach (var shade in new[] { 0, -19, -25 })
- {
- original = original
- .Replace(ColorToHex(LightenDarkenColor(color.Original, shade)), ColorToHex(LightenDarkenColor(color.Replacement, shade)), StringComparison.OrdinalIgnoreCase)
- .Replace(ColorToDec(LightenDarkenColor(color.Original, shade)), ColorToDec(LightenDarkenColor(color.Replacement, shade)), StringComparison.OrdinalIgnoreCase);
- }
- }
-
- return Task.FromResult(original);
- }
-
- ///
- /// converts color to the hex string representation
- ///
- ///
- ///
- private string ColorToHex(Color color) => $"#{color.R.ToString("X2")}{color.G.ToString("X2")}{color.B.ToString("X2")}";
-
- ///
- /// converts color to the rgb tuples representation
- ///
- ///
- ///
- private string ColorToDec(Color color) => $"{(int)color.R}, {(int)color.G}, {(int)color.B}";
-
- ///
- /// lightens or darkens a color on the given amount
- /// Based off SASS darken/lighten function
- ///
- ///
- ///
- ///
- private Color LightenDarkenColor(Color color, float amount)
- {
- int r = color.R + (int)((amount / 100.0f) * color.R);
-
- if (r > 255) r = 255;
- else if (r < 0) r = 0;
-
- int g = color.G + (int)((amount / 100.0f) * color.G);
-
- if (g > 255) g = 255;
- else if (g < 0) g = 0;
-
- int b = color.B + (int)((amount / 100.0f) * color.B);
-
- if (b > 255) b = 255;
- else if (b < 0) b = 0;
-
- return Color.FromArgb(r, g, b);
- }
- }
-}
diff --git a/WebfrontCore/Program.cs b/WebfrontCore/Program.cs
index 12e6784bf..e4127878a 100644
--- a/WebfrontCore/Program.cs
+++ b/WebfrontCore/Program.cs
@@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using SharedLibraryCore.Configuration;
using SharedLibraryCore.Interfaces;
-using WebfrontCore.Middleware;
namespace WebfrontCore
{
@@ -24,11 +23,6 @@ namespace WebfrontCore
public static Task GetWebHostTask(CancellationToken cancellationToken)
{
- var config = _webHost.Services.GetRequiredService();
- Manager.MiddlewareActionHandler.Register(null,
- new CustomCssAccentMiddlewareAction("#007ACC", "#fd7e14", config.WebfrontPrimaryColor,
- config.WebfrontSecondaryColor), "custom_css_accent");
-
return _webHost?.RunAsync(cancellationToken);
}
@@ -41,7 +35,12 @@ namespace WebfrontCore
.UseContentRoot(SharedLibraryCore.Utilities.OperatingDirectory)
#endif
.UseUrls(bindUrl)
- .UseKestrel()
+ .UseKestrel(cfg =>
+ {
+ cfg.Limits.MaxConcurrentConnections =
+ int.Parse(Environment.GetEnvironmentVariable("MaxConcurrentRequests") ?? "1");
+ cfg.Limits.KeepAliveTimeout = TimeSpan.FromSeconds(30);
+ })
.ConfigureServices(registerDependenciesAction)
.UseStartup()
.Build();
diff --git a/WebfrontCore/Startup.cs b/WebfrontCore/Startup.cs
index 2eb8ddd8f..5d6bed659 100644
--- a/WebfrontCore/Startup.cs
+++ b/WebfrontCore/Startup.cs
@@ -4,7 +4,6 @@ using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -24,9 +23,6 @@ using System.Reflection;
using System.Threading.Tasks;
using Data.Abstractions;
using Data.Helpers;
-using IW4MAdmin.Plugins.Stats.Helpers;
-using Stats.Client.Abstractions;
-using Stats.Config;
using WebfrontCore.Controllers.API.Validation;
using WebfrontCore.Middleware;
using WebfrontCore.QueryHelpers;
@@ -50,6 +46,12 @@ namespace WebfrontCore
.AllowAnyHeader();
});
});
+
+ services.AddStackPolicy(options =>
+ {
+ options.MaxConcurrentRequests = int.Parse(Environment.GetEnvironmentVariable("MaxConcurrentRequests") ?? "1");
+ options.RequestQueueLimit = int.Parse(Environment.GetEnvironmentVariable("RequestQueueLimit") ?? "1");
+ });
IEnumerable pluginAssemblies()
{
@@ -132,6 +134,7 @@ namespace WebfrontCore
app.UseMiddleware(serviceProvider.GetService>(), serviceProvider.GetRequiredService().WebfrontConnectionWhitelist);
}
+ app.UseConcurrencyLimiter();
app.UseStaticFiles();
app.UseAuthentication();
app.UseCors("AllowAll");
diff --git a/WebfrontCore/WebfrontCore.csproj b/WebfrontCore/WebfrontCore.csproj
index 910054a7c..510703229 100644
--- a/WebfrontCore/WebfrontCore.csproj
+++ b/WebfrontCore/WebfrontCore.csproj
@@ -25,7 +25,7 @@
- false
+ true
true
true
Latest
@@ -47,6 +47,7 @@
+