using IW4MAdmin.Application.Migration; using IW4MAdmin.Application.Misc; using Microsoft.Extensions.DependencyInjection; using SharedLibraryCore; using SharedLibraryCore.Configuration; using SharedLibraryCore.Exceptions; using SharedLibraryCore.Helpers; using SharedLibraryCore.Interfaces; using System; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace IW4MAdmin.Application { public class Program { public static BuildNumber Version { get; private set; } = BuildNumber.Parse(Utilities.GetVersionAsString()); public static ApplicationManager ServerManager; private static Task ApplicationTask; private static readonly BuildNumber _fallbackVersion = BuildNumber.Parse("99.99.99.99"); /// /// entrypoint of the application /// /// public static async Task Main() { AppDomain.CurrentDomain.SetData("DataDirectory", Utilities.OperatingDirectory); Console.OutputEncoding = Encoding.UTF8; Console.ForegroundColor = ConsoleColor.Gray; Console.CancelKeyPress += new ConsoleCancelEventHandler(OnCancelKey); Console.WriteLine("====================================================="); Console.WriteLine(" IW4MAdmin"); Console.WriteLine(" by RaidMax "); Console.WriteLine($" Version {Utilities.GetVersionAsString()}"); Console.WriteLine("====================================================="); await LaunchAsync(); } /// /// event callback executed when the control + c combination is detected /// gracefully stops the server manager and waits for all tasks to finish /// /// /// private static async void OnCancelKey(object sender, ConsoleCancelEventArgs e) { ServerManager?.Stop(); await ApplicationTask; } /// /// task that initializes application and starts the application monitoring and runtime tasks /// /// private static async Task LaunchAsync() { restart: try { var services = ConfigureServices(); using (var builder = services.BuildServiceProvider()) { ServerManager = (ApplicationManager)builder.GetRequiredService(); } // do any needed housekeeping file/folder migrations ConfigurationMigration.MoveConfigFolder10518(null); ConfigurationMigration.CheckDirectories(); ServerManager.Logger.WriteInfo(Utilities.CurrentLocalization.LocalizationIndex["MANAGER_VERSION"].FormatExt(Version)); await CheckVersion(); await ServerManager.Init(); } catch (Exception e) { var loc = Utilities.CurrentLocalization.LocalizationIndex; string failMessage = loc == null ? "Failed to initalize IW4MAdmin" : loc["MANAGER_INIT_FAIL"]; string exitMessage = loc == null ? "Press any key to exit..." : loc["MANAGER_EXIT"]; Console.WriteLine(failMessage); while (e.InnerException != null) { e = e.InnerException; } Console.WriteLine(e.Message); if (e is ConfigurationException cfgE) { foreach (string error in cfgE.Errors) { Console.WriteLine(error); } } Console.WriteLine(exitMessage); Console.ReadKey(); return; } try { ApplicationTask = RunApplicationTasksAsync(); await ApplicationTask; } catch { } if (ServerManager.IsRestartRequested) { goto restart; } } /// /// runs the core application tasks /// /// private static async Task RunApplicationTasksAsync() { var webfrontTask = ServerManager.GetApplicationSettings().Configuration().EnableWebFront ? WebfrontCore.Program.Init(ServerManager, ServerManager.CancellationToken) : Task.CompletedTask; // 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()); inputThread.Start(); var tasks = new[] { ServerManager.Start(), webfrontTask, }; await Task.WhenAll(tasks); ServerManager.Logger.WriteVerbose(Utilities.CurrentLocalization.LocalizationIndex["MANAGER_SHUTDOWN_SUCCESS"]); } /// /// checks for latest version of the application /// notifies user if an update is available /// /// private static async Task CheckVersion() { var api = API.Master.Endpoint.Get(); var loc = Utilities.CurrentLocalization.LocalizationIndex; var version = new API.Master.VersionInfo() { CurrentVersionStable = _fallbackVersion }; try { version = await api.GetVersion(1); } catch (Exception e) { ServerManager.Logger.WriteWarning(loc["MANAGER_VERSION_FAIL"]); while (e.InnerException != null) { e = e.InnerException; } ServerManager.Logger.WriteDebug(e.Message); } if (version.CurrentVersionStable == _fallbackVersion) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(loc["MANAGER_VERSION_FAIL"]); Console.ForegroundColor = ConsoleColor.Gray; } #if !PRERELEASE else if (version.CurrentVersionStable > Version) { Console.ForegroundColor = ConsoleColor.DarkYellow; Console.WriteLine($"IW4MAdmin {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionStable.ToString()}]"); Console.WriteLine(loc["MANAGER_VERSION_CURRENT"].FormatExt($"[v{Version.ToString()}]")); Console.ForegroundColor = ConsoleColor.Gray; } #else else if (version.CurrentVersionPrerelease > Version) { Console.ForegroundColor = ConsoleColor.DarkYellow; Console.WriteLine($"IW4MAdmin-Prerelease {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionPrerelease.ToString()}-pr]"); Console.WriteLine(loc["MANAGER_VERSION_CURRENT"].FormatExt($"[v{Version.ToString()}-pr]")); Console.ForegroundColor = ConsoleColor.Gray; } #endif else { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine(loc["MANAGER_VERSION_SUCCESS"]); Console.ForegroundColor = ConsoleColor.Gray; } } /// /// reads input from the console and executes entered commands on the default server /// /// private static async Task ReadConsoleInput() { string lastCommand; var Origin = Utilities.IW4MAdminClient(ServerManager.Servers[0]); try { while (!ServerManager.CancellationToken.IsCancellationRequested) { lastCommand = Console.ReadLine(); if (lastCommand?.Length > 0) { if (lastCommand?.Length > 0) { GameEvent E = new GameEvent() { Type = GameEvent.EventType.Command, Data = lastCommand, Origin = Origin, Owner = ServerManager.Servers[0] }; ServerManager.GetEventHandler().AddEvent(E); await E.WaitAsync(Utilities.DefaultCommandTimeout, ServerManager.CancellationToken); Console.Write('>'); } } } } catch (OperationCanceledException) { } } /// /// Configures the dependency injection services /// private static IServiceCollection ConfigureServices() { var serviceProvider = new ServiceCollection(); serviceProvider.AddSingleton() .AddSingleton(_serviceProvider => new BaseConfigurationHandler("IW4MAdminSettings").Configuration()) .AddSingleton(_serviceProvider => new BaseConfigurationHandler("CommandConfiguration").Configuration()) .AddSingleton(_serviceProvider => new Logger("IW4MAdmin-Manager")) .AddSingleton() .AddSingleton(_serviceProvider => { var config = _serviceProvider.GetRequiredService(); return Localization.Configure.Initialize(config?.UseLocalTranslations ?? false, config?.EnableCustomLocale ?? false ? (config.CustomLocale ?? "en-US") : "en-US"); }); foreach (var commandDefinition in typeof(SharedLibraryCore.Commands.QuitCommand).Assembly.GetTypes().Where(_command => _command.BaseType == typeof(Command))) { serviceProvider.AddTransient(typeof(IManagerCommand), commandDefinition); } return serviceProvider; } } }