From 7171b3753e1b3915533ebbe0a4b75d793c5a0c34 Mon Sep 17 00:00:00 2001 From: RaidMax Date: Wed, 26 Jan 2022 14:42:23 -0600 Subject: [PATCH] Address some .NET 6 oddities and allow webfront startup without servers being monitored --- Application/BuildScripts/PostBuild.bat | 3 +- Application/Main.cs | 89 ++++++++++---------- Application/Misc/BaseConfigurationHandler.cs | 34 ++++++-- Application/Misc/ScriptPlugin.cs | 8 +- 4 files changed, 76 insertions(+), 58 deletions(-) diff --git a/Application/BuildScripts/PostBuild.bat b/Application/BuildScripts/PostBuild.bat index c3cbc996c..c57f82646 100644 --- a/Application/BuildScripts/PostBuild.bat +++ b/Application/BuildScripts/PostBuild.bat @@ -13,4 +13,5 @@ if not exist "%TargetDir%Plugins" ( md "%TargetDir%Plugins" ) -xcopy /y "%SolutionDir%Build\Plugins" "%TargetDir%Plugins\" \ No newline at end of file +xcopy /y "%SolutionDir%Build\Plugins" "%TargetDir%Plugins\" +del "%TargetDir%Plugins\SQLite*" diff --git a/Application/Main.cs b/Application/Main.cs index 11d784faa..991f3b437 100644 --- a/Application/Main.cs +++ b/Application/Main.cs @@ -40,7 +40,7 @@ namespace IW4MAdmin.Application { public class Program { - public static BuildNumber Version { get; private set; } = BuildNumber.Parse(Utilities.GetVersionAsString()); + public static BuildNumber Version { get; } = BuildNumber.Parse(Utilities.GetVersionAsString()); public static ApplicationManager ServerManager; private static Task ApplicationTask; private static ServiceProvider serviceProvider; @@ -56,7 +56,7 @@ namespace IW4MAdmin.Application Console.OutputEncoding = Encoding.UTF8; Console.ForegroundColor = ConsoleColor.Gray; - Console.CancelKeyPress += new ConsoleCancelEventHandler(OnCancelKey); + Console.CancelKeyPress += OnCancelKey; Console.WriteLine("====================================================="); Console.WriteLine(" IW4MAdmin"); @@ -93,8 +93,8 @@ namespace IW4MAdmin.Application var logger = BuildDefaultLogger(new ApplicationConfiguration()); Utilities.DefaultLogger = logger; IServiceCollection services = null; - logger.LogInformation("Begin IW4MAdmin startup. Version is {version} {@args}", Version, args); - + logger.LogInformation("Begin IW4MAdmin startup. Version is {Version} {@Args}", Version, args); + try { // do any needed housekeeping file/folder migrations @@ -108,16 +108,23 @@ namespace IW4MAdmin.Application ServerManager = (ApplicationManager) serviceProvider.GetRequiredService(); translationLookup = serviceProvider.GetRequiredService(); - await versionChecker.CheckVersion(); - await ServerManager.Init(); + ApplicationTask = RunApplicationTasksAsync(logger, services); + var tasks = new[] + { + versionChecker.CheckVersion(), + ServerManager.Init(), + ApplicationTask + }; + + await Task.WhenAll(tasks); } catch (Exception e) { - string failMessage = translationLookup == null + var failMessage = translationLookup == null ? "Failed to initialize IW4MAdmin" : translationLookup["MANAGER_INIT_FAIL"]; - string exitMessage = translationLookup == null + var exitMessage = translationLookup == null ? "Press enter to exit..." : translationLookup["MANAGER_EXIT"]; @@ -137,7 +144,7 @@ namespace IW4MAdmin.Application .FormatExt(configException.ConfigurationFileName)); } - foreach (string error in configException.Errors) + foreach (var error in configException.Errors) { Console.WriteLine(error); } @@ -153,27 +160,12 @@ namespace IW4MAdmin.Application return; } - try - { - ApplicationTask = RunApplicationTasksAsync(logger, services); - await ApplicationTask; - } - - catch (Exception e) - { - logger.LogCritical(e, "Failed to launch IW4MAdmin"); - string failMessage = translationLookup == null - ? "Failed to launch IW4MAdmin" - : translationLookup["MANAGER_INIT_FAIL"]; - Console.WriteLine($"{failMessage}: {e.GetExceptionInfo()}"); - } - if (ServerManager.IsRestartRequested) { goto restart; } - serviceProvider.Dispose(); + await serviceProvider.DisposeAsync(); } /// @@ -190,13 +182,15 @@ namespace IW4MAdmin.Application // we want to run this one on a manual thread instead of letting the thread pool handle it, // because we can't exit early from waiting on console input, and it prevents us from restarting - var inputThread = new Thread(async () => await ReadConsoleInput(logger)); + async void ReadInput() => await ReadConsoleInput(logger); + + var inputThread = new Thread(ReadInput); inputThread.Start(); var tasks = new[] { - ServerManager.Start(), webfrontTask, + ServerManager.Start(), serviceProvider.GetRequiredService() .RunUploadStatus(ServerManager.CancellationToken), collectionService.BeginCollectionAsync(cancellationToken: ServerManager.CancellationToken) @@ -208,8 +202,7 @@ namespace IW4MAdmin.Application logger.LogInformation("Shutdown completed successfully"); Console.WriteLine(Utilities.CurrentLocalization.LocalizationIndex["MANAGER_SHUTDOWN_SUCCESS"]); } - - + /// /// reads input from the console and executes entered commands on the default server /// @@ -223,7 +216,7 @@ namespace IW4MAdmin.Application } string lastCommand; - var Origin = Utilities.IW4MAdminClient(ServerManager.Servers[0]); + EFClient origin = null; try { @@ -231,23 +224,27 @@ namespace IW4MAdmin.Application { lastCommand = await Console.In.ReadLineAsync(); - if (lastCommand?.Length > 0) + if (lastCommand == null) { - if (lastCommand?.Length > 0) - { - GameEvent E = new GameEvent() - { - Type = GameEvent.EventType.Command, - Data = lastCommand, - Origin = Origin, - Owner = ServerManager.Servers[0] - }; - - ServerManager.AddEvent(E); - await E.WaitAsync(Utilities.DefaultCommandTimeout, ServerManager.CancellationToken); - Console.Write('>'); - } + continue; } + + if (!lastCommand.Any()) + { + continue; + } + + var gameEvent = new GameEvent + { + Type = GameEvent.EventType.Command, + Data = lastCommand, + Origin = origin ??= Utilities.IW4MAdminClient(ServerManager.Servers.FirstOrDefault()), + Owner = ServerManager.Servers[0] + }; + + ServerManager.AddEvent(gameEvent); + await gameEvent.WaitAsync(Utilities.DefaultCommandTimeout, ServerManager.CancellationToken); + Console.Write('>'); } } catch (OperationCanceledException) @@ -355,7 +352,7 @@ namespace IW4MAdmin.Application { appConfig = (ApplicationConfiguration) new ApplicationConfiguration().Generate(); appConfigHandler.Set(appConfig); - appConfigHandler.Save(); + appConfigHandler.Save().RunSynchronously(); } // register override level names diff --git a/Application/Misc/BaseConfigurationHandler.cs b/Application/Misc/BaseConfigurationHandler.cs index 17dc053d1..95fc2e36b 100644 --- a/Application/Misc/BaseConfigurationHandler.cs +++ b/Application/Misc/BaseConfigurationHandler.cs @@ -4,6 +4,7 @@ using SharedLibraryCore.Exceptions; using SharedLibraryCore.Interfaces; using System; using System.IO; +using System.Threading; using System.Threading.Tasks; namespace IW4MAdmin.Application.Misc @@ -15,16 +16,23 @@ namespace IW4MAdmin.Application.Misc public class BaseConfigurationHandler : IConfigurationHandler where T : IBaseConfiguration { T _configuration; + private readonly SemaphoreSlim _onSaving; public BaseConfigurationHandler(string fn) { + _onSaving = new SemaphoreSlim(1, 1); FileName = Path.Join(Utilities.OperatingDirectory, "Configuration", $"{fn}.json"); Build(); } public BaseConfigurationHandler() : this(typeof(T).Name) { - + _onSaving = new SemaphoreSlim(1, 1); + } + + ~BaseConfigurationHandler() + { + _onSaving.Dispose(); } public string FileName { get; } @@ -54,14 +62,26 @@ namespace IW4MAdmin.Application.Misc public async Task Save() { - var settings = new JsonSerializerSettings() + try { - Formatting = Formatting.Indented - }; - settings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()); + await _onSaving.WaitAsync(); + var settings = new JsonSerializerSettings() + { + Formatting = Formatting.Indented + }; + settings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()); - var appConfigJson = JsonConvert.SerializeObject(_configuration, settings); - await File.WriteAllTextAsync(FileName, appConfigJson); + var appConfigJson = JsonConvert.SerializeObject(_configuration, settings); + await File.WriteAllTextAsync(FileName, appConfigJson); + } + + finally + { + if (_onSaving.CurrentCount == 0) + { + _onSaving.Release(1); + } + } } public T Configuration() diff --git a/Application/Misc/ScriptPlugin.cs b/Application/Misc/ScriptPlugin.cs index dd8e02c93..0b8509e64 100644 --- a/Application/Misc/ScriptPlugin.cs +++ b/Application/Misc/ScriptPlugin.cs @@ -268,17 +268,17 @@ namespace IW4MAdmin.Application.Misc } } - public Task OnLoadAsync(IManager manager) + public async Task OnLoadAsync(IManager manager) { _logger.LogDebug("OnLoad executing for {name}", Name); _scriptEngine.SetValue("_manager", manager); - return Task.FromResult(_scriptEngine.Execute("plugin.onLoadAsync(_manager)").GetCompletionValue()); + await Task.FromResult(_scriptEngine.Execute("plugin.onLoadAsync(_manager)").GetCompletionValue()); } - public Task OnTickAsync(Server S) + public async Task OnTickAsync(Server S) { _scriptEngine.SetValue("_server", S); - return Task.FromResult(_scriptEngine.Execute("plugin.onTickAsync(_server)").GetCompletionValue()); + await Task.FromResult(_scriptEngine.Execute("plugin.onTickAsync(_server)").GetCompletionValue()); } public async Task OnUnloadAsync()