From 25a73c986c4cb182e79b94e376f449f073820604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Jurczyk?= Date: Mon, 28 Dec 2020 19:42:34 +0100 Subject: [PATCH 01/11] Added config class. --- IO/Config/Config.cs | 187 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 IO/Config/Config.cs diff --git a/IO/Config/Config.cs b/IO/Config/Config.cs new file mode 100644 index 0000000..33b61c2 --- /dev/null +++ b/IO/Config/Config.cs @@ -0,0 +1,187 @@ +using System; +using System.Text; + +namespace LocalAdmin.V2.IO.Config +{ + public class Config + { + private static readonly string[] SplitArray = new[] {": "}; + + public bool LaShowStdoutStderr; + public bool LaNoSetCursor; + public bool EnableLaLogs = true; + public bool LaLogAutoFlush = true; + public bool LaLogStdoutStderr = true; + public bool LaDeleteOldLogs = true; + public ushort LaLogsExpirationDays = 90; + public bool DeleteOldRoundLogs = false; + public ushort RoundLogsExpirationDays = 180; + public bool CompressOldRoundLogs = false; + public ushort RoundLogsCompressionThresholdDays = 14; + + public string SerializeConfig() + { + var sb = new StringBuilder(); + + sb.Append("la_show_stdout_and_stderr: "); + sb.AppendLine(LaShowStdoutStderr.ToString().ToLowerInvariant()); + + sb.Append("la_no_set_cursor: "); + sb.AppendLine(LaNoSetCursor.ToString().ToLowerInvariant()); + + sb.Append("enable_la_logs: "); + sb.AppendLine(EnableLaLogs.ToString().ToLowerInvariant()); + + sb.Append("la_log_auto_flush: "); + sb.AppendLine(LaLogAutoFlush.ToString().ToLowerInvariant()); + + sb.Append("la_log_stdout_and_stderr: "); + sb.AppendLine(LaLogStdoutStderr.ToString().ToLowerInvariant()); + + sb.Append("la_delete_old_logs: "); + sb.AppendLine(LaDeleteOldLogs.ToString().ToLowerInvariant()); + + sb.Append("la_logs_expiration_days: "); + sb.AppendLine(LaLogsExpirationDays.ToString()); + + sb.Append("delete_old_round_logs: "); + sb.AppendLine(DeleteOldRoundLogs.ToString().ToLowerInvariant()); + + sb.Append("round_logs_expiration_days: "); + sb.AppendLine(RoundLogsExpirationDays.ToString()); + + sb.Append("compress_old_round_logs: "); + sb.AppendLine(CompressOldRoundLogs.ToString().ToLowerInvariant()); + + sb.Append("round_logs_compression_threshold_days: "); + sb.AppendLine(RoundLogsCompressionThresholdDays.ToString()); + + return sb.ToString(); + } + + public static Config DeserializeConfig(string[] lines) + { + var cfg = new Config(); + + foreach (var line in lines) + { + if (!line.Contains(": ", StringComparison.Ordinal)) + continue; + + var sp = line.Split(SplitArray, StringSplitOptions.None); + if (sp.Length != 2) + continue; + + switch (sp[0].ToLowerInvariant()) + { + case "la_show_stdout_and_stderr" when bool.TryParse(sp[1], out var b): + cfg.LaShowStdoutStderr = b; + break; + + case "la_no_set_cursor" when bool.TryParse(sp[1], out var b): + cfg.LaNoSetCursor = b; + break; + + case "enable_la_logs" when bool.TryParse(sp[1], out var b): + cfg.EnableLaLogs = b; + break; + + case "la_log_auto_flush" when bool.TryParse(sp[1], out var b): + cfg.LaLogAutoFlush = b; + break; + + case "la_log_stdout_and_stderr" when bool.TryParse(sp[1], out var b): + cfg.LaLogStdoutStderr = b; + break; + + case "la_delete_old_logs" when bool.TryParse(sp[1], out var b): + cfg.LaDeleteOldLogs = b; + break; + + case "la_logs_expiration_days" when ushort.TryParse(sp[1], out var b): + cfg.LaLogsExpirationDays = b; + break; + + case "delete_old_round_logs" when bool.TryParse(sp[1], out var b): + cfg.DeleteOldRoundLogs = b; + break; + + case "round_logs_expiration_days" when ushort.TryParse(sp[1], out var b): + cfg.RoundLogsExpirationDays = b; + break; + + case "compress_old_round_logs" when bool.TryParse(sp[1], out var b): + cfg.CompressOldRoundLogs = b; + break; + + case "round_logs_compression_threshold_days" when ushort.TryParse(sp[1], out var b): + cfg.RoundLogsCompressionThresholdDays = b; + break; + } + + if (!cfg.EnableLaLogs || cfg.LaLogsExpirationDays == 0) + cfg.LaDeleteOldLogs = false; + + if (cfg.RoundLogsExpirationDays == 0) + cfg.DeleteOldRoundLogs = false; + + if (cfg.RoundLogsCompressionThresholdDays == 0) + cfg.CompressOldRoundLogs = false; + + if (cfg.DeleteOldRoundLogs && cfg.RoundLogsExpirationDays <= cfg.RoundLogsCompressionThresholdDays) + cfg.CompressOldRoundLogs = false; + } + + return cfg; + } + + public override string ToString() + { + var sb = new StringBuilder(); + + sb.Append("- Show standard outputs (stdin and stderr): "); + sb.AppendLine(LaShowStdoutStderr.ToString().ToLowerInvariant()); + + sb.Append("- Disable cursor position management: "); + sb.AppendLine(LaNoSetCursor.ToString().ToLowerInvariant()); + + sb.Append("- Enable LocalAdmin logs: "); + sb.AppendLine(EnableLaLogs.ToString().ToLowerInvariant()); + + if (EnableLaLogs) + { + sb.Append("- Enable LocalAdmin logs auto flushing: "); + sb.AppendLine(LaLogAutoFlush.ToString().ToLowerInvariant()); + + sb.Append("- Enable logging standard outputs: "); + sb.AppendLine(LaLogStdoutStderr.ToString().ToLowerInvariant()); + + if (LaDeleteOldLogs) + { + sb.Append("- Delete LocalAdmin logs older than "); + sb.Append(LaLogsExpirationDays); + sb.AppendLine(" days"); + } + else sb.AppendLine("- Don't delete old LocalAdmin logs."); + } + + if (DeleteOldRoundLogs) + { + sb.Append("- Delete round logs older than "); + sb.Append(RoundLogsExpirationDays); + sb.AppendLine(" days"); + } + else sb.AppendLine("- Don't delete old round logs."); + + if (CompressOldRoundLogs) + { + sb.Append("- Compress round logs older than "); + sb.Append(RoundLogsCompressionThresholdDays); + sb.AppendLine(" days"); + } + else sb.AppendLine("- Don't compress old round logs."); + + return sb.ToString(); + } + } +} \ No newline at end of file From 34be0bebd52572fca21c6b11badf75c2be68dc46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Jurczyk?= Date: Mon, 28 Dec 2020 22:14:55 +0100 Subject: [PATCH 02/11] Development --- Core/ConfigWizard.cs | 208 ++++++++++++++++++++++++++++++++++ Core/LocalAdmin.cs | 112 ++++++++++++++++-- IO/ConsoleUtil.cs | 36 +++--- LocalAdmin V2.sln.DotSettings | 1 + 4 files changed, 331 insertions(+), 26 deletions(-) create mode 100644 Core/ConfigWizard.cs diff --git a/Core/ConfigWizard.cs b/Core/ConfigWizard.cs new file mode 100644 index 0000000..1916029 --- /dev/null +++ b/Core/ConfigWizard.cs @@ -0,0 +1,208 @@ +using System; +using System.IO; +using System.Text; +using LocalAdmin.V2.IO.Config; + +namespace LocalAdmin.V2.Core +{ + public static class ConfigWizard + { + public static void RunConfigWizard() + { + var curConfig = LocalAdmin.Configuration; + + Retry: + Console.WriteLine("Welcome to LocalAdmin Configuration Wizard!"); + Console.WriteLine(); + Console.WriteLine( + "We will ask you a couple of questions. You can always change your answers by running LocalAdmin with \"--reconfigure\" argument or manually editing configuration files in " + + LocalAdmin.GameUserDataRoot + "config directory."); + Console.WriteLine(); + + Console.WriteLine(LocalAdmin.Configuration == null ? "This is the default LocalAdmin configuration:" : "That's your current LocalAdmin configuration:"); + LocalAdmin.Configuration ??= new Config(); + Console.WriteLine(LocalAdmin.Configuration.ToString()); + + Console.WriteLine(); + var input = string.Empty; + while (input == null || !input.Equals("edit", StringComparison.OrdinalIgnoreCase) && + !input.Equals("keep", StringComparison.OrdinalIgnoreCase)) + { + Console.Write("Do you want to edit that configuration? [edit/keep]: "); + input = Console.ReadLine(); + } + + if (input.Equals("keep", StringComparison.OrdinalIgnoreCase)) + { + SaveConfig(); + return; + } + + LocalAdmin.Configuration.LaShowStdoutStderr = BoolInput("Should standard outputs (stdout and stderr) be visible on the LocalAdmin console?"); + LocalAdmin.Configuration.LaNoSetCursor = BoolInput("Should cursor position management be disabled (enable only if you are experiencing issues with the cursor)?"); + LocalAdmin.Configuration.EnableLaLogs = BoolInput("Do you want to enable LocalAdmin logs?"); + + if (LocalAdmin.Configuration.EnableLaLogs) + { + LocalAdmin.Configuration.LaLogAutoFlush = BoolInput("Should LocalAdmin logs be automatically flushed (file updated in real time - may affect performance)?"); + LocalAdmin.Configuration.LaLogStdoutStderr = BoolInput("Do you want to enable standard outputs logging?"); + LocalAdmin.Configuration.LaDeleteOldLogs = BoolInput("Do you want to automatically delete old LocalAdmin logs (older than a specified amount of days)?"); + + if (LocalAdmin.Configuration.LaDeleteOldLogs) + LocalAdmin.Configuration.LaLogsExpirationDays = UshortInput("How many days LocalAdmin logs should be kept?"); + } + + LocalAdmin.Configuration.DeleteOldRoundLogs = BoolInput("Do you want to automatically delete old round logs (older than a specified amount of days)?"); + if (LocalAdmin.Configuration.DeleteOldRoundLogs) + LocalAdmin.Configuration.RoundLogsExpirationDays = UshortInput("How many days round logs should be kept?"); + + LocalAdmin.Configuration.CompressOldRoundLogs = BoolInput("Do you want to automatically compress old round logs (older than a specified amount of days)?"); + if (LocalAdmin.Configuration.CompressOldRoundLogs) + LocalAdmin.Configuration.RoundLogsCompressionThresholdDays = UshortInput("How many days round logs should be kept uncompressed?"); + + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine("Your new configuration:"); + Console.WriteLine(LocalAdmin.Configuration.ToString()); + Console.WriteLine(); + + if (BoolInput("Save configuration?")) + { + SaveConfig(); + return; + } + + Console.WriteLine(); + LocalAdmin.Configuration = curConfig; + goto Retry; + } + + private static bool BoolInput(string question) + { + while (true) + { + Console.Write(question + " [yes/no]: "); + var input = Console.ReadLine(); + + if (input == null) continue; + if (input.Equals("y", StringComparison.OrdinalIgnoreCase) || + input.Equals("yes", StringComparison.OrdinalIgnoreCase)) + return true; + if (input.Equals("n", StringComparison.OrdinalIgnoreCase) || + input.Equals("no", StringComparison.OrdinalIgnoreCase)) + return false; + } + } + + private static ushort UshortInput(string question) + { + while (true) + { + Console.Write(question + " "); + var input = Console.ReadLine(); + + if (input == null) continue; + if (ushort.TryParse(input, out var u)) + return u; + } + } + + private static void SaveConfig() + { + var input = string.Empty; + while (input == null || !input.Equals("this", StringComparison.OrdinalIgnoreCase) && + !input.Equals("global", StringComparison.OrdinalIgnoreCase)) + { + Console.Write($"Do you want to save the configuration only for THIS server (on port {LocalAdmin.Singleton.GamePort} or should it become a GLOBAL configuration (default one for all future servers - servers not configured yet)? [this/global]: "); + input = Console.ReadLine(); + } + + var cfgPath = LocalAdmin.GameUserDataRoot + "config" + Path.PathSeparator + LocalAdmin.Singleton.GamePort + Path.PathSeparator + + "config_localadmin.txt"; + + if (input.Equals("this", StringComparison.OrdinalIgnoreCase)) + { + if (File.Exists(cfgPath)) + { + try + { + File.Delete(cfgPath); + } + catch (Exception e) + { + Console.WriteLine("FATAL ERROR: Can't delete config file."); + Console.WriteLine("Path: " + cfgPath); + Console.WriteLine("Exception: " + e.Message); + Environment.Exit(1); + return; + } + } + + try + { + File.WriteAllText(cfgPath, LocalAdmin.Configuration!.SerializeConfig(), Encoding.UTF8); + } + catch (Exception e) + { + Console.WriteLine("FATAL ERROR: Can't write config file."); + Console.WriteLine("Path: " + cfgPath); + Console.WriteLine("Exception: " + e.Message); + Environment.Exit(1); + return; + } + + Console.WriteLine("Configuration saved!"); + return; + } + + if (File.Exists(cfgPath)) + { + try + { + File.Delete(cfgPath); + } + catch (Exception e) + { + Console.WriteLine("FATAL ERROR: Can't delete **LOCAL** config file."); + Console.WriteLine("Path: " + cfgPath); + Console.WriteLine("Exception: " + e.Message); + Environment.Exit(1); + return; + } + } + + cfgPath = LocalAdmin.GameUserDataRoot + "config" + Path.PathSeparator + "config_localadmin_global.txt"; + + if (File.Exists(cfgPath)) + { + try + { + File.Delete(cfgPath); + } + catch (Exception e) + { + Console.WriteLine("FATAL ERROR: Can't delete **GLOBAL** config file."); + Console.WriteLine("Path: " + cfgPath); + Console.WriteLine("Exception: " + e.Message); + Environment.Exit(1); + return; + } + } + + try + { + File.WriteAllText(cfgPath, LocalAdmin.Configuration!.SerializeConfig(), Encoding.UTF8); + } + catch (Exception e) + { + Console.WriteLine("FATAL ERROR: Can't write **GLOBAL** config file."); + Console.WriteLine("Path: " + cfgPath); + Console.WriteLine("Exception: " + e.Message); + Environment.Exit(1); + return; + } + + Console.WriteLine("Configuration saved!"); + } + } +} \ No newline at end of file diff --git a/Core/LocalAdmin.cs b/Core/LocalAdmin.cs index c5af77f..faa3840 100644 --- a/Core/LocalAdmin.cs +++ b/Core/LocalAdmin.cs @@ -8,8 +8,10 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices; +using System.Text; using System.Threading; using System.Threading.Tasks; +using LocalAdmin.V2.IO.Config; using LocalAdmin.V2.IO.Logging; namespace LocalAdmin.V2.Core @@ -45,6 +47,8 @@ public sealed class LocalAdmin : IDisposable internal static bool NoSetCursor, PrintControlMessages, AutoFlush = true, EnableLogging = true; private volatile bool processClosing; + internal static Config? Configuration; + private LocalAdmin() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) @@ -87,6 +91,8 @@ public void Start(string[] args) } var passArgs = false; + var reconfigure = false; + foreach (var arg in args) { if (passArgs) @@ -95,34 +101,85 @@ public void Start(string[] args) continue; } - switch (arg) + if (arg.StartsWith("-", StringComparison.Ordinal) && + !arg.StartsWith("--", StringComparison.Ordinal) && arg.Length > 1) + { + for (int i = 1; i < arg.Length; i++) + { + switch (arg[i]) + { + case 'c': + NoSetCursor = true; + break; + + case 'p': + PrintControlMessages = true; + break; + + case 'n': + AutoFlush = false; + break; + + case 'l': + EnableLogging = false; + break; + + case 'r': + reconfigure = true; + break; + } + } + } + else switch (arg) { - case "-c": case "--noSetCursor": NoSetCursor = true; break; - case "-p": case "--printControl": PrintControlMessages = true; break; - case "-n": case "--noAutoFlush": AutoFlush = false; break; - case "-l": case "--noLogs": EnableLogging = false; break; + case "--reconfigure": + reconfigure = true; + break; + case "--": passArgs = true; break; } } + var cfgPath = GameUserDataRoot + "config" + Path.PathSeparator + GamePort + Path.PathSeparator + + "config_localadmin.txt"; + + if (File.Exists(cfgPath)) + Configuration = Config.DeserializeConfig(File.ReadAllLines(cfgPath, Encoding.UTF8)); + else + { + cfgPath = GameUserDataRoot + "config" + Path.PathSeparator + "config_localadmin_global.txt"; + + if (File.Exists(cfgPath)) + Configuration = Config.DeserializeConfig(File.ReadAllLines(cfgPath, Encoding.UTF8)); + else + reconfigure = true; + } + + if (reconfigure) + ConfigWizard.RunConfigWizard(); + + NoSetCursor |= Configuration!.LaNoSetCursor; + AutoFlush &= Configuration!.LaLogAutoFlush; + EnableLogging &= Configuration!.EnableLaLogs; + try { SetupExitHandlers(); @@ -140,15 +197,15 @@ public void Start(string[] args) readerTask!.Start(); if (!EnableLogging) - ConsoleUtil.WriteLine("Logging has been disabled using startup argument.", ConsoleColor.Red); + ConsoleUtil.WriteLine("Logging has been disabled.", ConsoleColor.Red); else if (!AutoFlush) - ConsoleUtil.WriteLine("Logs auto flush has been disabled using startup argument.", ConsoleColor.Yellow); + ConsoleUtil.WriteLine("Logs auto flush has been disabled.", ConsoleColor.Yellow); if (PrintControlMessages) ConsoleUtil.WriteLine("Printing control messages been enabled using startup argument.", ConsoleColor.Gray); if (NoSetCursor) - ConsoleUtil.WriteLine("Cursor management been disabled using startup argument.", ConsoleColor.Gray); + ConsoleUtil.WriteLine("Cursor management been disabled.", ConsoleColor.Gray); Task.WaitAll(readerTask); @@ -341,15 +398,50 @@ private void RunScpsl(ushort port) if (File.Exists(scpslExecutable)) { ConsoleUtil.WriteLine("Executing: " + scpslExecutable, ConsoleColor.DarkGreen); - + var redirectStreams = Configuration!.LaShowStdoutStderr || Configuration!.LaLogStdoutStderr; + var startInfo = new ProcessStartInfo { FileName = scpslExecutable, Arguments = $"-batchmode -nographics -nodedicateddelete -port{port} -console{server!.ConsolePort} -id{Process.GetCurrentProcess().Id} {gameArguments}", - CreateNoWindow = true + CreateNoWindow = true, + UseShellExecute = false, + RedirectStandardOutput = redirectStreams, + RedirectStandardError = redirectStreams, }; gameProcess = Process.Start(startInfo); + + if (!redirectStreams) return; + gameProcess!.OutputDataReceived += (sender, args) => + { + if (string.IsNullOrWhiteSpace(args.Data)) + return; + + ConsoleUtil.WriteLine("[STDOUT] " + args.Data, ConsoleColor.Gray, log: Configuration!.LaLogStdoutStderr, display: Configuration!.LaShowStdoutStderr); + }; + + gameProcess!.ErrorDataReceived += (sender, args) => + { + if (string.IsNullOrWhiteSpace(args.Data)) + return; + + ConsoleUtil.WriteLine("[STDERR] " + args.Data, ConsoleColor.DarkMagenta, log: Configuration!.LaLogStdoutStderr, display: Configuration!.LaShowStdoutStderr); + }; + + gameProcess!.BeginOutputReadLine(); + gameProcess!.BeginErrorReadLine(); + + gameProcess!.Exited += (sender, args) => + { + if (processClosing) + return; + + ConsoleUtil.WriteLine("The game process has been terminated...", ConsoleColor.Red); + Exit(0, true); + }; + + gameProcess!.EnableRaisingEvents = true; } else { diff --git a/IO/ConsoleUtil.cs b/IO/ConsoleUtil.cs index 6b8352d..daf8393 100644 --- a/IO/ConsoleUtil.cs +++ b/IO/ConsoleUtil.cs @@ -49,33 +49,37 @@ public static void Write(string content, ConsoleColor color = ConsoleColor.White public static string GetTimestamp() => $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff zzz}]"; - public static void WriteLine(string content, ConsoleColor color = ConsoleColor.White, int height = 0) + public static void WriteLine(string content, ConsoleColor color = ConsoleColor.White, int height = 0, bool log = true, bool display = true) { lock (_lck) { content = content.Trim().Trim(ToTrim); content = string.IsNullOrEmpty(content) ? string.Empty : $"{GetTimestamp()} {content}"; - Console.BackgroundColor = ConsoleColor.Black; - - try - { - Console.ForegroundColor = color; - } - catch + if (display) { - Console.ForegroundColor = ConsoleColor.White; - } + Console.BackgroundColor = ConsoleColor.Black; - if (height > 0 && !Core.LocalAdmin.NoSetCursor) - Console.CursorTop += height; + try + { + Console.ForegroundColor = color; + } + catch + { + Console.ForegroundColor = ConsoleColor.White; + } - Console.WriteLine(content); + if (height > 0 && !Core.LocalAdmin.NoSetCursor) + Console.CursorTop += height; - Console.ForegroundColor = ConsoleColor.White; - Console.BackgroundColor = ConsoleColor.Black; + Console.WriteLine(content); - Logger.Log(content); + Console.ForegroundColor = ConsoleColor.White; + Console.BackgroundColor = ConsoleColor.Black; + } + + if (log) + Logger.Log(content); } } } diff --git a/LocalAdmin V2.sln.DotSettings b/LocalAdmin V2.sln.DotSettings index f02d1fc..52f5af2 100644 --- a/LocalAdmin V2.sln.DotSettings +++ b/LocalAdmin V2.sln.DotSettings @@ -1,3 +1,4 @@  + True True True \ No newline at end of file From 5addbcdc2c08fbcfaf11b6f96b35e5031e7be009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Jurczyk?= Date: Mon, 28 Dec 2020 23:44:54 +0100 Subject: [PATCH 03/11] Added log cleaner, bumped version --- Core/ConfigWizard.cs | 2 +- Core/LocalAdmin.cs | 9 +- IO/{Config => }/Config.cs | 4 +- IO/Logging/ConsoleLogEntry.cs | 18 --- IO/Logging/LogCleaner.cs | 208 ++++++++++++++++++++++++++++++++++ IO/Logging/Logger.cs | 6 +- 6 files changed, 219 insertions(+), 28 deletions(-) rename IO/{Config => }/Config.cs (98%) delete mode 100644 IO/Logging/ConsoleLogEntry.cs create mode 100644 IO/Logging/LogCleaner.cs diff --git a/Core/ConfigWizard.cs b/Core/ConfigWizard.cs index 1916029..6395932 100644 --- a/Core/ConfigWizard.cs +++ b/Core/ConfigWizard.cs @@ -1,7 +1,7 @@ using System; using System.IO; using System.Text; -using LocalAdmin.V2.IO.Config; +using LocalAdmin.V2.IO; namespace LocalAdmin.V2.Core { diff --git a/Core/LocalAdmin.cs b/Core/LocalAdmin.cs index faa3840..46db87d 100644 --- a/Core/LocalAdmin.cs +++ b/Core/LocalAdmin.cs @@ -11,7 +11,6 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -using LocalAdmin.V2.IO.Config; using LocalAdmin.V2.IO.Logging; namespace LocalAdmin.V2.Core @@ -29,7 +28,7 @@ namespace LocalAdmin.V2.Core public sealed class LocalAdmin : IDisposable { - public const string VersionString = "2.3.0"; + public const string VersionString = "2.3.1"; public static readonly LocalAdmin Singleton = new LocalAdmin(); public ushort GamePort { get; private set; } @@ -206,6 +205,9 @@ public void Start(string[] args) if (NoSetCursor) ConsoleUtil.WriteLine("Cursor management been disabled.", ConsoleColor.Gray); + + if (Configuration.LaDeleteOldLogs || Configuration.DeleteOldRoundLogs || Configuration.CompressOldRoundLogs) + LogCleaner.Initialize(); Task.WaitAll(readerTask); @@ -495,11 +497,10 @@ public void Exit(int code = -1, bool waitForKey = false) lock (this) { if (processClosing) - { return; - } processClosing = true; + LogCleaner.Abort(); Logger.EndLogging(); TerminateGame(); // Forcefully terminating the process gameProcess?.Dispose(); diff --git a/IO/Config/Config.cs b/IO/Config.cs similarity index 98% rename from IO/Config/Config.cs rename to IO/Config.cs index 33b61c2..6392ddf 100644 --- a/IO/Config/Config.cs +++ b/IO/Config.cs @@ -1,11 +1,11 @@ using System; using System.Text; -namespace LocalAdmin.V2.IO.Config +namespace LocalAdmin.V2.IO { public class Config { - private static readonly string[] SplitArray = new[] {": "}; + private static readonly string[] SplitArray = {": "}; public bool LaShowStdoutStderr; public bool LaNoSetCursor; diff --git a/IO/Logging/ConsoleLogEntry.cs b/IO/Logging/ConsoleLogEntry.cs deleted file mode 100644 index bf71c41..0000000 --- a/IO/Logging/ConsoleLogEntry.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace LocalAdmin.V2.IO.Logging -{ - /* - public class ConsoleLogEntry - { - public readonly string Content; - public readonly ConsoleColor Color; - public readonly int Height; - - public ConsoleLogEntry(string c, ConsoleColor co, int h) - { - Content = c; - Color = co; - Height = h; - } - } - */ -} diff --git a/IO/Logging/LogCleaner.cs b/IO/Logging/LogCleaner.cs new file mode 100644 index 0000000..18419ab --- /dev/null +++ b/IO/Logging/LogCleaner.cs @@ -0,0 +1,208 @@ +using System; +using System.Globalization; +using System.IO; +using System.IO.Compression; +using System.Text; +using System.Threading; + +namespace LocalAdmin.V2.IO.Logging +{ + public static class LogCleaner + { + private static bool _abort; + private static Thread? _cleanupThread; + private static DateTime? _lastCleanup; + + internal static void Initialize() + { + if (_abort || _cleanupThread != null) + return; + + _cleanupThread = new Thread(Cleanup) + { + Name = "LocalAdmin logs cleanup", + Priority = ThreadPriority.Lowest, + IsBackground = true + }; + + _cleanupThread.Start(); + } + + internal static bool Abort() => _abort = true; + + private static void Cleanup() + { + while (!_abort) + { + if (_abort) + return; + + var now = DateTime.Now; + + if (_lastCleanup == null) + { + _lastCleanup = DateTime.UtcNow; + + for (uint i = 0; i < 15 * 2 && !_abort; i++) + Thread.Sleep(500); + } + else if (now.DayOfYear == _lastCleanup.Value.DayOfYear) + continue; + else + { + for (uint i = 0; i < 30 * 60 * 2 && !_abort; i++) + Thread.Sleep(500); + } + + if (Core.LocalAdmin.Configuration!.DeleteOldRoundLogs || + Core.LocalAdmin.Configuration!.CompressOldRoundLogs) + { + var root = Core.LocalAdmin.GameUserDataRoot + "ServerLogs" + Path.PathSeparator + + Core.LocalAdmin.Singleton.GamePort + Path.PathSeparator; + + if (Directory.Exists(root)) + { + foreach (var file in Directory.GetFiles(root, "Round *", SearchOption.TopDirectoryOnly)) + { + string stage = string.Empty; + + try + { + if (_abort) + return; + + stage = "Processing file name"; + var name = Path.GetFileName(file); + if (name.Length < 25 || !name.StartsWith("Round ", StringComparison.Ordinal)) + continue; + + var d = name.Substring(6, 10); + if (!DateTime.TryParseExact(d, "yyyy-MM-dd", + CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var date)) + continue; + + var diff = (now - date); + + stage = "File name processed"; + if (Core.LocalAdmin.Configuration!.DeleteOldRoundLogs && diff.TotalDays > + Core.LocalAdmin.Configuration!.RoundLogsExpirationDays) + { + stage = "Deletion"; + File.Delete(file); + continue; + } + + if (Core.LocalAdmin.Configuration!.CompressOldRoundLogs && diff.TotalDays > + Core.LocalAdmin.Configuration!.RoundLogsCompressionThresholdDays) + { + stage = "Compression - p2"; + var p2 = root + "LA-ToCompress-" + d + Path.PathSeparator; + if (!Directory.Exists(p2)) + Directory.CreateDirectory(p2); + + stage = "Compression - moving"; + File.Move(file, p2 + name); + } + + stage = "End"; + } + catch (Exception e) + { + ConsoleUtil.WriteLine($"[Log Maintenance] Failed to process old round log {file}. Processing stage: {stage}. Exception: {e.Message}", ConsoleColor.Red); + } + } + + foreach (var dir in Directory.GetDirectories(root, "LA-ToCompress-*", SearchOption.TopDirectoryOnly)) + { + string stage = string.Empty; + + try + { + if (_abort) + return; + + stage = "Processing directory name"; + var name = Path.GetDirectoryName(dir); + if (name == null || name.Length != 24 || !name.StartsWith("LA-ToCompress-", StringComparison.Ordinal)) + continue; + + var d = root + "Round Logs Archive " + name.Substring(14); + + if (Directory.Exists(d)) + { + ConsoleUtil.WriteLine($"[Log Maintenance] Failed to compress old round log directory. Target directory already exists.", ConsoleColor.Red); + continue; + } + + if (File.Exists(d + ".zip")) + { + ConsoleUtil.WriteLine($"[Log Maintenance] Failed to compress old round log directory. Target ZIP file already exists.", ConsoleColor.Red); + continue; + } + + stage = "Renaming directory"; + Directory.Move(dir, d); + + stage = "Compressing directory"; + ZipFile.CreateFromDirectory(d, d + ".zip", CompressionLevel.Optimal, true, Encoding.UTF8); + + stage = "Removing uncompressed directory"; + Directory.Delete(d, true); + + stage = "End"; + } + catch (Exception e) + { + ConsoleUtil.WriteLine($"[Log Maintenance] Failed to compress old round log directory {dir}. Processing stage: {stage}. Exception: {e.Message}", ConsoleColor.Red); + } + } + } + } + + if (Core.LocalAdmin.Configuration!.LaDeleteOldLogs) + { + var root = Core.LocalAdmin.GameUserDataRoot + Logger.LogFolderName + Path.DirectorySeparatorChar + Core.LocalAdmin.Singleton.GamePort + Path.DirectorySeparatorChar; + if (Directory.Exists(root)) + { + foreach (var file in Directory.GetFiles(root, "LocalAdmin Log *", SearchOption.TopDirectoryOnly)) + { + string stage = string.Empty; + + try + { + if (_abort) + return; + + stage = "Processing file name"; + var name = Path.GetFileName(file); + if (name.Length < 34 || !name.StartsWith("LocalAdmin Log ", StringComparison.Ordinal)) + continue; + + var d = name.Substring(15, 10); + if (!DateTime.TryParseExact(d, "yyyy-MM-dd", + CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var date)) + continue; + + var diff = (now - date); + + stage = "File name processed"; + if (diff.TotalDays > Core.LocalAdmin.Configuration!.LaLogsExpirationDays) + { + stage = "Deletion"; + File.Delete(file); + continue; + } + + stage = "End"; + } + catch (Exception e) + { + ConsoleUtil.WriteLine($"[Log Maintenance] Failed to process old LocalAdmin log {file}. Processing stage: {stage}. Exception: {e.Message}", ConsoleColor.Red); + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/IO/Logging/Logger.cs b/IO/Logging/Logger.cs index 80e0f69..0bb90a6 100644 --- a/IO/Logging/Logger.cs +++ b/IO/Logging/Logger.cs @@ -6,7 +6,7 @@ namespace LocalAdmin.V2.IO.Logging public static class Logger { private static StreamWriter? _sw; - private const string LogFolderName = "LocalAdminLogs"; + internal const string LogFolderName = "LocalAdminLogs"; public static void Initialize() { @@ -15,11 +15,11 @@ public static void Initialize() if (_sw != null) EndLogging(); - string dir = Core.LocalAdmin.GameUserDataRoot + LogFolderName + Path.DirectorySeparatorChar + Core.LocalAdmin.Singleton.GamePort; + string dir = Core.LocalAdmin.GameUserDataRoot + LogFolderName + Path.DirectorySeparatorChar + Core.LocalAdmin.Singleton.GamePort + Path.DirectorySeparatorChar; if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); - _sw = new StreamWriter(dir + Path.DirectorySeparatorChar + + _sw = new StreamWriter(dir + $"LocalAdmin Log {DateTime.Now:yyyy-MM-dd HH.mm.ss}.txt") {AutoFlush = Core.LocalAdmin.AutoFlush}; Log($"{ConsoleUtil.GetTimestamp()} Logging started."); From ebbcd666aff13c47958027c17b7cd66e24e4f423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Jurczyk?= Date: Mon, 28 Dec 2020 23:52:09 +0100 Subject: [PATCH 04/11] README.md update (added --reconfigure argument to the list) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 157328a..63e4841 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Linux: `./LocalAdmin [port] [arguments] [-- arguments passthrough]` # Arguments list | Long version | Short version | Description | | --- | --- | --- | +| --reconfigure | -r | Opens configuration editor. | | --noSetCursor | -c | Disables setting console cursor position. | | --printControl | -p | Enables printing control messages. | | --noLogs | -l | Disables LocalAdmin logging. | From b7fe404a0217d0824acdc29e5c93f4a25a9031da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Jurczyk?= Date: Tue, 29 Dec 2020 00:00:51 +0100 Subject: [PATCH 05/11] Log cleaner improvements --- IO/Logging/LogCleaner.cs | 47 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/IO/Logging/LogCleaner.cs b/IO/Logging/LogCleaner.cs index 18419ab..b5b8511 100644 --- a/IO/Logging/LogCleaner.cs +++ b/IO/Logging/LogCleaner.cs @@ -73,7 +73,8 @@ private static void Cleanup() stage = "Processing file name"; var name = Path.GetFileName(file); - if (name.Length < 25 || !name.StartsWith("Round ", StringComparison.Ordinal)) + if (name.Length < 25 || !name.StartsWith("Round ", StringComparison.Ordinal) || + !name.EndsWith(".txt", StringComparison.Ordinal)) continue; var d = name.Substring(6, 10); @@ -81,7 +82,7 @@ private static void Cleanup() CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var date)) continue; - var diff = (now - date); + var diff = now - date; stage = "File name processed"; if (Core.LocalAdmin.Configuration!.DeleteOldRoundLogs && diff.TotalDays > @@ -111,6 +112,45 @@ private static void Cleanup() ConsoleUtil.WriteLine($"[Log Maintenance] Failed to process old round log {file}. Processing stage: {stage}. Exception: {e.Message}", ConsoleColor.Red); } } + + foreach (var file in Directory.GetFiles(root, "Round Logs Archive *", SearchOption.TopDirectoryOnly)) + { + string stage = string.Empty; + + try + { + if (_abort) + return; + + stage = "Processing file name"; + var name = Path.GetFileName(file); + if (name.Length < 29 || !name.StartsWith("Round Logs Archive ", StringComparison.Ordinal) || + !name.EndsWith(".zip", StringComparison.Ordinal)) + continue; + + var d = name.Substring(19, 10); + if (!DateTime.TryParseExact(d, "yyyy-MM-dd", + CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var date)) + continue; + + var diff = now - date; + + stage = "File name processed"; + if (Core.LocalAdmin.Configuration!.DeleteOldRoundLogs && diff.TotalDays > + Core.LocalAdmin.Configuration!.RoundLogsExpirationDays) + { + stage = "Deletion"; + File.Delete(file); + continue; + } + + stage = "End"; + } + catch (Exception e) + { + ConsoleUtil.WriteLine($"[Log Maintenance] Failed to process old archive of round logs {file}. Processing stage: {stage}. Exception: {e.Message}", ConsoleColor.Red); + } + } foreach (var dir in Directory.GetDirectories(root, "LA-ToCompress-*", SearchOption.TopDirectoryOnly)) { @@ -175,7 +215,8 @@ private static void Cleanup() stage = "Processing file name"; var name = Path.GetFileName(file); - if (name.Length < 34 || !name.StartsWith("LocalAdmin Log ", StringComparison.Ordinal)) + if (name.Length < 34 || !name.StartsWith("LocalAdmin Log ", StringComparison.Ordinal) || + !name.EndsWith(".txt", StringComparison.Ordinal)) continue; var d = name.Substring(15, 10); From b39d124f77556c10486f7cdf7c021e8ef7f2dd81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Jurczyk?= Date: Tue, 29 Dec 2020 13:01:46 +0100 Subject: [PATCH 06/11] Path fixes --- Core/ConfigWizard.cs | 8 ++++---- Core/LocalAdmin.cs | 29 +++++++++++++---------------- IO/Logging/LogCleaner.cs | 9 ++++++--- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Core/ConfigWizard.cs b/Core/ConfigWizard.cs index 6395932..91c7f37 100644 --- a/Core/ConfigWizard.cs +++ b/Core/ConfigWizard.cs @@ -116,9 +116,9 @@ private static void SaveConfig() Console.Write($"Do you want to save the configuration only for THIS server (on port {LocalAdmin.Singleton.GamePort} or should it become a GLOBAL configuration (default one for all future servers - servers not configured yet)? [this/global]: "); input = Console.ReadLine(); } - - var cfgPath = LocalAdmin.GameUserDataRoot + "config" + Path.PathSeparator + LocalAdmin.Singleton.GamePort + Path.PathSeparator + - "config_localadmin.txt"; + + var cfgPath = + $"{LocalAdmin.GameUserDataRoot}config{Path.PathSeparator}{LocalAdmin.Singleton.GamePort}{Path.PathSeparator}config_localadmin.txt"; if (input.Equals("this", StringComparison.OrdinalIgnoreCase)) { @@ -171,7 +171,7 @@ private static void SaveConfig() } } - cfgPath = LocalAdmin.GameUserDataRoot + "config" + Path.PathSeparator + "config_localadmin_global.txt"; + cfgPath = $"{LocalAdmin.GameUserDataRoot}config{Path.PathSeparator}config_localadmin_global.txt"; if (File.Exists(cfgPath)) { diff --git a/Core/LocalAdmin.cs b/Core/LocalAdmin.cs index 46db87d..839f0a1 100644 --- a/Core/LocalAdmin.cs +++ b/Core/LocalAdmin.cs @@ -30,7 +30,7 @@ public sealed class LocalAdmin : IDisposable { public const string VersionString = "2.3.1"; public static readonly LocalAdmin Singleton = new LocalAdmin(); - public ushort GamePort { get; private set; } + public ushort GamePort; private readonly CommandService commandService = new CommandService(); private Process? gameProcess; @@ -69,8 +69,7 @@ public void Start(string[] args) try { - ushort port = 0; - if (args.Length == 0 || !ushort.TryParse(args[0], out port)) + if (args.Length == 0 || !ushort.TryParse(args[0], out GamePort)) { ConsoleUtil.WriteLine("You can pass port number as first startup argument.", ConsoleColor.Green); Console.WriteLine(string.Empty); @@ -79,8 +78,8 @@ public void Start(string[] args) ReadInput((input) => { if (!string.IsNullOrEmpty(input)) - return ushort.TryParse(input, out port); - port = 7777; + return ushort.TryParse(input, out GamePort); + GamePort = 7777; return true; }, () => { }, () => @@ -157,14 +156,13 @@ public void Start(string[] args) } } - var cfgPath = GameUserDataRoot + "config" + Path.PathSeparator + GamePort + Path.PathSeparator + - "config_localadmin.txt"; + var cfgPath = $"{GameUserDataRoot}config{Path.PathSeparator}{GamePort}{Path.PathSeparator}config_localadmin.txt"; if (File.Exists(cfgPath)) Configuration = Config.DeserializeConfig(File.ReadAllLines(cfgPath, Encoding.UTF8)); else { - cfgPath = GameUserDataRoot + "config" + Path.PathSeparator + "config_localadmin_global.txt"; + cfgPath = $"{GameUserDataRoot}config{Path.PathSeparator}config_localadmin_global.txt"; if (File.Exists(cfgPath)) Configuration = Config.DeserializeConfig(File.ReadAllLines(cfgPath, Encoding.UTF8)); @@ -191,7 +189,7 @@ public void Start(string[] args) RegisterCommands(); SetupReader(); - StartSession(port); + StartSession(); readerTask!.Start(); @@ -230,7 +228,7 @@ public void Start(string[] args) /// if the session has already begun, /// then terminates it. /// - public void StartSession(ushort port) + public void StartSession() { // Terminate the game, if the game process is exists if (gameProcess != null && !gameProcess.HasExited) @@ -238,13 +236,12 @@ public void StartSession(ushort port) Menu(); - BaseWindowTitle = $"LocalAdmin v. {VersionString} on port {port}"; + BaseWindowTitle = $"LocalAdmin v. {VersionString} on port {GamePort}"; Console.Title = BaseWindowTitle; - GamePort = port; Logger.Initialize(); - ConsoleUtil.WriteLine($"Started new session on port {port}.", ConsoleColor.DarkGreen); + ConsoleUtil.WriteLine($"Started new session on port {GamePort}.", ConsoleColor.DarkGreen); ConsoleUtil.WriteLine("Trying to start server...", ConsoleColor.Gray); SetupServer(); @@ -252,7 +249,7 @@ public void StartSession(ushort port) while (server!.ConsolePort == 0) Thread.Sleep(200); - RunScpsl(port); + RunScpsl(); } private void Menu() @@ -395,7 +392,7 @@ private void SetupReader() }); } - private void RunScpsl(ushort port) + private void RunScpsl() { if (File.Exists(scpslExecutable)) { @@ -405,7 +402,7 @@ private void RunScpsl(ushort port) var startInfo = new ProcessStartInfo { FileName = scpslExecutable, - Arguments = $"-batchmode -nographics -nodedicateddelete -port{port} -console{server!.ConsolePort} -id{Process.GetCurrentProcess().Id} {gameArguments}", + Arguments = $"-batchmode -nographics -nodedicateddelete -port{GamePort} -console{server!.ConsolePort} -id{Process.GetCurrentProcess().Id} {gameArguments}", CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = redirectStreams, diff --git a/IO/Logging/LogCleaner.cs b/IO/Logging/LogCleaner.cs index b5b8511..4e1b9e3 100644 --- a/IO/Logging/LogCleaner.cs +++ b/IO/Logging/LogCleaner.cs @@ -53,12 +53,13 @@ private static void Cleanup() for (uint i = 0; i < 30 * 60 * 2 && !_abort; i++) Thread.Sleep(500); } + + ConsoleUtil.WriteLine("Log cleanup started"); if (Core.LocalAdmin.Configuration!.DeleteOldRoundLogs || Core.LocalAdmin.Configuration!.CompressOldRoundLogs) { - var root = Core.LocalAdmin.GameUserDataRoot + "ServerLogs" + Path.PathSeparator + - Core.LocalAdmin.Singleton.GamePort + Path.PathSeparator; + var root = $"{Core.LocalAdmin.GameUserDataRoot}ServerLogs{Path.PathSeparator}{Core.LocalAdmin.Singleton.GamePort}{Path.PathSeparator}"; if (Directory.Exists(root)) { @@ -201,7 +202,7 @@ private static void Cleanup() if (Core.LocalAdmin.Configuration!.LaDeleteOldLogs) { - var root = Core.LocalAdmin.GameUserDataRoot + Logger.LogFolderName + Path.DirectorySeparatorChar + Core.LocalAdmin.Singleton.GamePort + Path.DirectorySeparatorChar; + var root = $"{Core.LocalAdmin.GameUserDataRoot}{Logger.LogFolderName}{Path.PathSeparator}{Core.LocalAdmin.Singleton.GamePort}{Path.PathSeparator}"; if (Directory.Exists(root)) { foreach (var file in Directory.GetFiles(root, "LocalAdmin Log *", SearchOption.TopDirectoryOnly)) @@ -243,6 +244,8 @@ private static void Cleanup() } } } + + ConsoleUtil.WriteLine("Log cleanup complete"); } } } From 976e9cfa058d9736a52af2cd73cbaece8da6ebc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Jurczyk?= Date: Tue, 29 Dec 2020 13:08:48 +0100 Subject: [PATCH 07/11] Fix --- Core/LocalAdmin.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Core/LocalAdmin.cs b/Core/LocalAdmin.cs index 839f0a1..9a56022 100644 --- a/Core/LocalAdmin.cs +++ b/Core/LocalAdmin.cs @@ -228,7 +228,7 @@ public void Start(string[] args) /// if the session has already begun, /// then terminates it. /// - public void StartSession() + public void StartSession(ushort port = 0) { // Terminate the game, if the game process is exists if (gameProcess != null && !gameProcess.HasExited) @@ -236,6 +236,9 @@ public void StartSession() Menu(); + if (port != 0) + GamePort = port; + BaseWindowTitle = $"LocalAdmin v. {VersionString} on port {GamePort}"; Console.Title = BaseWindowTitle; From fdab2bdcd097b24a50f6a9f46338f4644bd1db65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Jurczyk?= Date: Tue, 29 Dec 2020 13:25:33 +0100 Subject: [PATCH 08/11] Fixes --- Core/ConfigWizard.cs | 4 ++-- Core/LocalAdmin.cs | 4 ++-- IO/Config.cs | 4 ++-- IO/Logging/LogCleaner.cs | 14 +++++--------- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/Core/ConfigWizard.cs b/Core/ConfigWizard.cs index 91c7f37..a3047e9 100644 --- a/Core/ConfigWizard.cs +++ b/Core/ConfigWizard.cs @@ -118,7 +118,7 @@ private static void SaveConfig() } var cfgPath = - $"{LocalAdmin.GameUserDataRoot}config{Path.PathSeparator}{LocalAdmin.Singleton.GamePort}{Path.PathSeparator}config_localadmin.txt"; + $"{LocalAdmin.GameUserDataRoot}config{Path.DirectorySeparatorChar}{LocalAdmin.Singleton.GamePort}{Path.DirectorySeparatorChar}config_localadmin.txt"; if (input.Equals("this", StringComparison.OrdinalIgnoreCase)) { @@ -171,7 +171,7 @@ private static void SaveConfig() } } - cfgPath = $"{LocalAdmin.GameUserDataRoot}config{Path.PathSeparator}config_localadmin_global.txt"; + cfgPath = $"{LocalAdmin.GameUserDataRoot}config{Path.DirectorySeparatorChar}config_localadmin_global.txt"; if (File.Exists(cfgPath)) { diff --git a/Core/LocalAdmin.cs b/Core/LocalAdmin.cs index 9a56022..f764d5c 100644 --- a/Core/LocalAdmin.cs +++ b/Core/LocalAdmin.cs @@ -156,13 +156,13 @@ public void Start(string[] args) } } - var cfgPath = $"{GameUserDataRoot}config{Path.PathSeparator}{GamePort}{Path.PathSeparator}config_localadmin.txt"; + var cfgPath = $"{GameUserDataRoot}config{Path.DirectorySeparatorChar}{GamePort}{Path.DirectorySeparatorChar}config_localadmin.txt"; if (File.Exists(cfgPath)) Configuration = Config.DeserializeConfig(File.ReadAllLines(cfgPath, Encoding.UTF8)); else { - cfgPath = $"{GameUserDataRoot}config{Path.PathSeparator}config_localadmin_global.txt"; + cfgPath = $"{GameUserDataRoot}config{Path.DirectorySeparatorChar}config_localadmin_global.txt"; if (File.Exists(cfgPath)) Configuration = Config.DeserializeConfig(File.ReadAllLines(cfgPath, Encoding.UTF8)); diff --git a/IO/Config.cs b/IO/Config.cs index 6392ddf..ad4b943 100644 --- a/IO/Config.cs +++ b/IO/Config.cs @@ -14,9 +14,9 @@ public class Config public bool LaLogStdoutStderr = true; public bool LaDeleteOldLogs = true; public ushort LaLogsExpirationDays = 90; - public bool DeleteOldRoundLogs = false; + public bool DeleteOldRoundLogs; public ushort RoundLogsExpirationDays = 180; - public bool CompressOldRoundLogs = false; + public bool CompressOldRoundLogs; public ushort RoundLogsCompressionThresholdDays = 14; public string SerializeConfig() diff --git a/IO/Logging/LogCleaner.cs b/IO/Logging/LogCleaner.cs index 4e1b9e3..c14552d 100644 --- a/IO/Logging/LogCleaner.cs +++ b/IO/Logging/LogCleaner.cs @@ -53,13 +53,11 @@ private static void Cleanup() for (uint i = 0; i < 30 * 60 * 2 && !_abort; i++) Thread.Sleep(500); } - - ConsoleUtil.WriteLine("Log cleanup started"); if (Core.LocalAdmin.Configuration!.DeleteOldRoundLogs || Core.LocalAdmin.Configuration!.CompressOldRoundLogs) { - var root = $"{Core.LocalAdmin.GameUserDataRoot}ServerLogs{Path.PathSeparator}{Core.LocalAdmin.Singleton.GamePort}{Path.PathSeparator}"; + var root = $"{Core.LocalAdmin.GameUserDataRoot}ServerLogs{Path.DirectorySeparatorChar}{Core.LocalAdmin.Singleton.GamePort}{Path.DirectorySeparatorChar}"; if (Directory.Exists(root)) { @@ -98,7 +96,7 @@ private static void Cleanup() Core.LocalAdmin.Configuration!.RoundLogsCompressionThresholdDays) { stage = "Compression - p2"; - var p2 = root + "LA-ToCompress-" + d + Path.PathSeparator; + var p2 = root + "LA-ToCompress-" + d + Path.DirectorySeparatorChar; if (!Directory.Exists(p2)) Directory.CreateDirectory(p2); @@ -163,8 +161,8 @@ private static void Cleanup() return; stage = "Processing directory name"; - var name = Path.GetDirectoryName(dir); - if (name == null || name.Length != 24 || !name.StartsWith("LA-ToCompress-", StringComparison.Ordinal)) + var name = new DirectoryInfo(dir).Name; + if (name.Length != 24 || !name.StartsWith("LA-ToCompress-", StringComparison.Ordinal)) continue; var d = root + "Round Logs Archive " + name.Substring(14); @@ -202,7 +200,7 @@ private static void Cleanup() if (Core.LocalAdmin.Configuration!.LaDeleteOldLogs) { - var root = $"{Core.LocalAdmin.GameUserDataRoot}{Logger.LogFolderName}{Path.PathSeparator}{Core.LocalAdmin.Singleton.GamePort}{Path.PathSeparator}"; + var root = $"{Core.LocalAdmin.GameUserDataRoot}{Logger.LogFolderName}{Path.DirectorySeparatorChar}{Core.LocalAdmin.Singleton.GamePort}{Path.DirectorySeparatorChar}"; if (Directory.Exists(root)) { foreach (var file in Directory.GetFiles(root, "LocalAdmin Log *", SearchOption.TopDirectoryOnly)) @@ -244,8 +242,6 @@ private static void Cleanup() } } } - - ConsoleUtil.WriteLine("Log cleanup complete"); } } } From 797889d9f2e58ba28a41d0add4b43eaa1a5ffda9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Jurczyk?= Date: Tue, 29 Dec 2020 13:35:54 +0100 Subject: [PATCH 09/11] Exit exception fix --- Core/LocalAdmin.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Core/LocalAdmin.cs b/Core/LocalAdmin.cs index f764d5c..657946a 100644 --- a/Core/LocalAdmin.cs +++ b/Core/LocalAdmin.cs @@ -504,7 +504,17 @@ public void Exit(int code = -1, bool waitForKey = false) Logger.EndLogging(); TerminateGame(); // Forcefully terminating the process gameProcess?.Dispose(); - readerTask?.Dispose(); + + try + { + if (readerTask != null && readerTask.IsCompleted) + readerTask?.Dispose(); + } + catch + { + //Ignore + } + if (waitForKey) { ConsoleUtil.WriteLine("Press any key to close...", ConsoleColor.DarkGray); From da3cbba6286df17f73ea35518aab6712085d18a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Jurczyk?= Date: Tue, 29 Dec 2020 14:59:55 +0100 Subject: [PATCH 10/11] Config wizard lang changes --- Core/ConfigWizard.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/ConfigWizard.cs b/Core/ConfigWizard.cs index a3047e9..8462187 100644 --- a/Core/ConfigWizard.cs +++ b/Core/ConfigWizard.cs @@ -38,8 +38,8 @@ public static void RunConfigWizard() return; } - LocalAdmin.Configuration.LaShowStdoutStderr = BoolInput("Should standard outputs (stdout and stderr) be visible on the LocalAdmin console?"); - LocalAdmin.Configuration.LaNoSetCursor = BoolInput("Should cursor position management be disabled (enable only if you are experiencing issues with the cursor)?"); + LocalAdmin.Configuration.LaShowStdoutStderr = BoolInput("Should standard outputs (contain a lot of debug information) be visible on the LocalAdmin console?"); + LocalAdmin.Configuration.LaNoSetCursor = BoolInput("Should cursor position management be DISABLED (disable only if you are experiencing issues with the console)?"); LocalAdmin.Configuration.EnableLaLogs = BoolInput("Do you want to enable LocalAdmin logs?"); if (LocalAdmin.Configuration.EnableLaLogs) From d4baf6e036b957093a6e7b699ab7743771307cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Jurczyk?= Date: Tue, 29 Dec 2020 15:22:48 +0100 Subject: [PATCH 11/11] Added default options (keep and global) --- Core/ConfigWizard.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Core/ConfigWizard.cs b/Core/ConfigWizard.cs index 8462187..751d092 100644 --- a/Core/ConfigWizard.cs +++ b/Core/ConfigWizard.cs @@ -24,15 +24,15 @@ public static void RunConfigWizard() Console.WriteLine(LocalAdmin.Configuration.ToString()); Console.WriteLine(); - var input = string.Empty; - while (input == null || !input.Equals("edit", StringComparison.OrdinalIgnoreCase) && + var input = "0"; + while (!string.IsNullOrWhiteSpace(input) && !input.Equals("edit", StringComparison.OrdinalIgnoreCase) && !input.Equals("keep", StringComparison.OrdinalIgnoreCase)) { Console.Write("Do you want to edit that configuration? [edit/keep]: "); input = Console.ReadLine(); } - if (input.Equals("keep", StringComparison.OrdinalIgnoreCase)) + if (string.IsNullOrWhiteSpace(input) || input.Equals("keep", StringComparison.OrdinalIgnoreCase)) { SaveConfig(); return; @@ -109,9 +109,9 @@ private static ushort UshortInput(string question) private static void SaveConfig() { - var input = string.Empty; - while (input == null || !input.Equals("this", StringComparison.OrdinalIgnoreCase) && - !input.Equals("global", StringComparison.OrdinalIgnoreCase)) + var input = "0"; + while (!string.IsNullOrWhiteSpace(input) && !input.Equals("this", StringComparison.OrdinalIgnoreCase) && + !input.Equals("global", StringComparison.OrdinalIgnoreCase)) { Console.Write($"Do you want to save the configuration only for THIS server (on port {LocalAdmin.Singleton.GamePort} or should it become a GLOBAL configuration (default one for all future servers - servers not configured yet)? [this/global]: "); input = Console.ReadLine(); @@ -120,7 +120,7 @@ private static void SaveConfig() var cfgPath = $"{LocalAdmin.GameUserDataRoot}config{Path.DirectorySeparatorChar}{LocalAdmin.Singleton.GamePort}{Path.DirectorySeparatorChar}config_localadmin.txt"; - if (input.Equals("this", StringComparison.OrdinalIgnoreCase)) + if (input != null && input.Equals("this", StringComparison.OrdinalIgnoreCase)) { if (File.Exists(cfgPath)) {