From 361ed37362b087d4d3a1c46209680364656ce829 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Sun, 6 Aug 2023 17:14:57 +0300 Subject: [PATCH] Reimplemented error handling for SettingsFile --- DiscordBot/Installer.cs | 55 +---------- DiscordBot/Program.cs | 18 ++-- PluginManager/Config.cs | 3 +- .../Interfaces/Exceptions/IException.cs | 17 ++++ PluginManager/Others/Enums.cs | 6 ++ .../Others/Exceptions/ConfigFailedToLoad.cs | 91 +++++++++++++++++++ .../Exceptions/ConfigNoKeyWasPresent.cs | 75 +++++++++++++++ PluginManager/Others/Logger/DBLogger.cs | 5 +- PluginManager/Others/SettingsDictionary.cs | 41 +++++++-- 9 files changed, 235 insertions(+), 76 deletions(-) create mode 100644 PluginManager/Interfaces/Exceptions/IException.cs create mode 100644 PluginManager/Others/Exceptions/ConfigFailedToLoad.cs create mode 100644 PluginManager/Others/Exceptions/ConfigNoKeyWasPresent.cs diff --git a/DiscordBot/Installer.cs b/DiscordBot/Installer.cs index 7a9e87e..4a596c2 100644 --- a/DiscordBot/Installer.cs +++ b/DiscordBot/Installer.cs @@ -46,59 +46,8 @@ public static class Installer public static async Task SetupPluginDatabase() { Console.WriteLine("The plugin database is required to run the bot but there is nothing configured yet."); - Console.WriteLine("Please select one option : "); - Console.WriteLine("1. Download the official database file"); - Console.WriteLine("2. Create a new (CUSTOM) database file"); - var choice = 0; - Console.Write("Choice : "); - choice = int.Parse(Console.ReadLine()); - if (choice != 1 && choice != 2) - { - Console.WriteLine("Invalid choice !"); - Console.WriteLine("Please restart the installer !"); - Console.ReadKey(); - Environment.Exit(0); - } - - if (choice == 1) - await DownloadPluginDatabase(); - - if (choice == 2) - { - Console.WriteLine("Do you have a url to a valid database file ? (y/n)"); - var answer = Console.ReadLine(); - if (answer == "y") - { - Console.WriteLine("Please enter the url :"); - var url = Console.ReadLine(); - await DownloadPluginDatabase(url); - return; - } - - Console.WriteLine("Do you want to create a new database file ? (y/n)"); - answer = Console.ReadLine(); - if (answer == "y") - { - Console.WriteLine("A new file will be generated at ./Data/Resources/URLs.json"); - Console.WriteLine("Please edit the file and restart the bot !"); - Directory.CreateDirectory("./Data/Resources"); - await File.WriteAllTextAsync("./Data/Resources/URLs.json", - @" - { - ""PluginList"": """", - ""PluginVersions"": """", - ""StartupMessage"": """", - ""SetupKeys"": """", - ""Versions"": """", - ""Changelog"": """", - ""LinuxBot"": """", - ""WindowsLauncher"": """", - } - ".Replace(" ", "") - ); - Environment.Exit(0); - } - } + Console.WriteLine("Downloading the default database..."); + await DownloadPluginDatabase(); } private static async Task DownloadPluginDatabase( diff --git a/DiscordBot/Program.cs b/DiscordBot/Program.cs index 8b63e8d..b927b1f 100644 --- a/DiscordBot/Program.cs +++ b/DiscordBot/Program.cs @@ -163,16 +163,9 @@ public class Program private static async Task PreLoadComponents(string[] args) { await Initialize(); - - if (!Directory.Exists("./Data/Resources") || !File.Exists("./Data/Resources/URLs.json")) - await Installer.SetupPluginDatabase(); - - - URLs = new SettingsDictionary("./Data/Resources/URLs.json"); - + Logger.LogEvent += (message, type, isInternal) => { - if (isInternal) return; if (type == LogLevel.INFO) Console.ForegroundColor = ConsoleColor.Green; else if (type == LogLevel.WARNING) @@ -186,6 +179,12 @@ public class Program Console.ResetColor(); }; + if (!Directory.Exists("./Data/Resources") || !File.Exists("./Data/Resources/URLs.json")) + await Installer.SetupPluginDatabase(); + + + URLs = new SettingsDictionary("./Data/Resources/URLs.json"); + Console.WriteLine("Loading resources ..."); @@ -212,8 +211,7 @@ public class Program Logger.Log(ex.ToString(), "Bot", LogLevel.ERROR); } } - - + var onlineSettingsList = await ServerCom.ReadTextFromURL(URLs["Versions"]); foreach (var key in onlineSettingsList) { diff --git a/PluginManager/Config.cs b/PluginManager/Config.cs index f3b31c4..16a7491 100644 --- a/PluginManager/Config.cs +++ b/PluginManager/Config.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Threading.Tasks; using PluginManager.Bot; using PluginManager.Others; diff --git a/PluginManager/Interfaces/Exceptions/IException.cs b/PluginManager/Interfaces/Exceptions/IException.cs new file mode 100644 index 0000000..ec79dc4 --- /dev/null +++ b/PluginManager/Interfaces/Exceptions/IException.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace PluginManager.Interfaces.Exceptions; + +public interface IException +{ + public List Messages { get; set; } + public bool isFatal { get; } + public string GenerateFullMessage(); + public void HandleException(); + + public IException AppendError(string message); + + public IException AppendError(List messages); + public IException IsFatal(bool isFatal = true); + +} \ No newline at end of file diff --git a/PluginManager/Others/Enums.cs b/PluginManager/Others/Enums.cs index 16b69e3..2dd071b 100644 --- a/PluginManager/Others/Enums.cs +++ b/PluginManager/Others/Enums.cs @@ -39,3 +39,9 @@ public enum InternalActionRunType ON_STARTUP, ON_CALL } + +internal enum ExceptionExitCode : int +{ + CONFIG_FAILED_TO_LOAD = 1, + CONFIG_KEY_NOT_FOUND = 2, +} diff --git a/PluginManager/Others/Exceptions/ConfigFailedToLoad.cs b/PluginManager/Others/Exceptions/ConfigFailedToLoad.cs new file mode 100644 index 0000000..7825ae2 --- /dev/null +++ b/PluginManager/Others/Exceptions/ConfigFailedToLoad.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using PluginManager.Interfaces.Exceptions; + +namespace PluginManager.Others.Exceptions; + +public class ConfigFailedToLoad : IException +{ + public List? Messages { get; set; } + public bool isFatal { get; private set; } + public string? File { get; } + + + public ConfigFailedToLoad(string message, bool isFatal, string file) + { + this.isFatal = isFatal; + Messages = new List() {message}; + this.File = file; + } + + public ConfigFailedToLoad(string message, bool isFatal) + { + this.isFatal = isFatal; + Messages = new List() {message}; + this.File = null; + } + + public ConfigFailedToLoad(string message) + { + this.isFatal = false; + Messages = new List() {message}; + this.File = null; + } + + public string GenerateFullMessage() + { + string messages = ""; + foreach (var message in Messages) + { + messages += message + "\n"; + } + return $"\nMessage: {messages}\nIsFatal: {isFatal}\nFile: {File ?? "null"}"; + } + + public void HandleException() + { + if (isFatal) + { + Config.Logger.Log(GenerateFullMessage(), LogLevel.CRITICAL, true); + Environment.Exit((int)ExceptionExitCode.CONFIG_FAILED_TO_LOAD); + + } + + Config.Logger.Log(GenerateFullMessage(), LogLevel.WARNING); + } + + public IException AppendError(string message) + { + Messages.Add(message); + return this; + } + + public IException AppendError(List messages) + { + Messages.AddRange(messages); + return this; + } + + public IException IsFatal(bool isFatal = true) + { + this.isFatal = isFatal; + return this; + } + + + public static ConfigFailedToLoad CreateError(string message, bool isFatal, string? file = null) + { + if (file is not null) + return new ConfigFailedToLoad(message, isFatal, file); + return new ConfigFailedToLoad(message, isFatal); + } + + public static ConfigFailedToLoad CreateError(string message) + { + return new ConfigFailedToLoad(message); + } + + + + +} \ No newline at end of file diff --git a/PluginManager/Others/Exceptions/ConfigNoKeyWasPresent.cs b/PluginManager/Others/Exceptions/ConfigNoKeyWasPresent.cs new file mode 100644 index 0000000..ea35911 --- /dev/null +++ b/PluginManager/Others/Exceptions/ConfigNoKeyWasPresent.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using PluginManager.Interfaces.Exceptions; + +namespace PluginManager.Others.Exceptions; + +public class ConfigNoKeyWasPresent: IException +{ + public List Messages { get; set; } + public bool isFatal { get; private set; } + + public ConfigNoKeyWasPresent(string message, bool isFatal) + { + this.Messages = new List() { message }; + this.isFatal = isFatal; + } + + public ConfigNoKeyWasPresent(string message) + { + this.Messages = new List() { message }; + this.isFatal = false; + } + + public string GenerateFullMessage() + { + string messages = ""; + foreach (var message in Messages) + { + messages += message + "\n"; + } + return $"\nMessage: {messages}\nIsFatal: {isFatal}"; + } + + public void HandleException() + { + if (isFatal) + { + + Config.Logger.Log(GenerateFullMessage(), LogLevel.CRITICAL, true); + Environment.Exit((int)ExceptionExitCode.CONFIG_KEY_NOT_FOUND); + + } + + Config.Logger.Log(GenerateFullMessage(), LogLevel.WARNING); + } + + public IException AppendError(string message) + { + Messages.Add(message); + return this; + } + + public IException AppendError(List messages) + { + Messages.AddRange(messages); + return this; + } + + public IException IsFatal(bool isFatal = true) + { + this.isFatal = isFatal; + return this; + } + + public static ConfigNoKeyWasPresent CreateError(string message) + { + return new ConfigNoKeyWasPresent(message); + } + + public static ConfigNoKeyWasPresent CreateError(string message, bool isFatal) + { + return new ConfigNoKeyWasPresent(message, isFatal); + } + +} \ No newline at end of file diff --git a/PluginManager/Others/Logger/DBLogger.cs b/PluginManager/Others/Logger/DBLogger.cs index bfd3977..44912e7 100644 --- a/PluginManager/Others/Logger/DBLogger.cs +++ b/PluginManager/Others/Logger/DBLogger.cs @@ -23,7 +23,7 @@ public class DBLogger public IReadOnlyList Logs => LogHistory; public IReadOnlyList Errors => ErrorHistory; - public event LogHandler LogEvent; + public event LogHandler? LogEvent; public void Log(string message, LogLevel type = LogLevel.INFO) { @@ -52,8 +52,7 @@ public class DBLogger public void Log(LogMessage message) { - if (LogEvent is not null) - LogEvent?.Invoke(message.Message, message.Type); + LogEvent?.Invoke(message.Message, message.Type); if (message.Type != LogLevel.ERROR && message.Type != LogLevel.CRITICAL) LogHistory.Add(message); diff --git a/PluginManager/Others/SettingsDictionary.cs b/PluginManager/Others/SettingsDictionary.cs index 86b95a3..3cb1602 100644 --- a/PluginManager/Others/SettingsDictionary.cs +++ b/PluginManager/Others/SettingsDictionary.cs @@ -1,8 +1,8 @@ -using System; -using System.Collections; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; +using PluginManager.Others.Exceptions; namespace PluginManager.Others; @@ -10,13 +10,16 @@ public class SettingsDictionary : IDictionary { public string? _file { get; } private IDictionary? _dictionary; - + public SettingsDictionary(string? file) { _file = file; if (!LoadFromFile()) { - throw new Exception($"Failed to load {file}. Please check the file and try again."); + ConfigFailedToLoad.CreateError("Failed to load config") + .AppendError("The file is empty or does not exist") + .IsFatal() + .HandleException(); } } @@ -31,8 +34,13 @@ public class SettingsDictionary : IDictionary if (!string.IsNullOrEmpty(_file)) try { - if (File.Exists(_file)){ - if (!File.ReadAllText(_file).Contains('{') && !File.ReadAllText(_file).Contains('}')) + if (File.Exists(_file)) + { + string FileContent = File.ReadAllText(_file); + if (string.IsNullOrEmpty(FileContent)) + File.WriteAllText(_file, "{}"); + + if(!FileContent.Contains("{") || !FileContent.Contains("}")) File.WriteAllText(_file, "{}"); } else @@ -40,9 +48,12 @@ public class SettingsDictionary : IDictionary _dictionary = JsonManager.ConvertFromJson>(_file).Result; return true; } - catch (Exception e) + catch { - Config.Logger.Error(e); + ConfigFailedToLoad + .CreateError("Failed to load config") + .IsFatal() + .HandleException(); return false; } @@ -109,7 +120,19 @@ public class SettingsDictionary : IDictionary public TValue this[TKey key] { - get => this._dictionary![key]; + get + { + if (this._dictionary!.ContainsKey(key)) + if(this._dictionary[key] is string s && !string.IsNullOrEmpty(s) && !string.IsNullOrWhiteSpace(s)) + return this._dictionary[key]; + + ConfigNoKeyWasPresent.CreateError($"Key {(key is string ? key : typeof(TKey).Name)} was not present in {_file ?? "config"}") + .AppendError("Deleting the file may fix this issue") + .IsFatal() + .HandleException(); + + return default!; + } set => this._dictionary![key] = value; }