diff --git a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs index c66609e..4f34f6e 100644 --- a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs +++ b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs @@ -211,79 +211,33 @@ internal static class PluginMethods internal static async Task LoadPlugins(string[] args) { var loader = new PluginLoader(Application.CurrentApplication.DiscordBotClient.Client); - if (args != null && (args.Length == 2 && args[1] == "-q")) + if (args != null && args.Contains("-q")) { await loader.LoadPlugins(); return true; } - - var cc = Console.ForegroundColor; - loader.OnCommandLoaded += (data) => + + loader.OnCommandLoaded += (command) => { - if (data.IsSuccess) - { - Application.Logger.Log("Successfully loaded command : " + data.PluginName, LogType.Info, "\t\t > {Message}"); - } - - else - { - Application.Logger.Log("Failed to load command : " + data.PluginName + " because " + data.ErrorMessage, - typeof(PluginMethods), LogType.Error - ); - } - - Console.ForegroundColor = cc; + Application.Logger.Log($"Command {command.Command} loaded successfully", LogType.Info); }; - loader.OnEventLoaded += (data) => + + loader.OnEventLoaded += (eEvent) => { - if (data.IsSuccess) - { - Application.Logger.Log("Successfully loaded event : " + data.PluginName, LogType.Info, "\t\t > {Message}"); - } - else - { - Application.Logger.Log("Failed to load event : " + data.PluginName + " because " + data.ErrorMessage, - typeof(PluginMethods), LogType.Error - ); - } - - Console.ForegroundColor = cc; + Application.Logger.Log($"Event {eEvent.Name} loaded successfully",LogType.Info); }; - - loader.OnSlashCommandLoaded += (data) => + + loader.OnActionLoaded += (action) => { - if (data.IsSuccess) - { - Application.Logger.Log("Successfully loaded slash command : " + data.PluginName, LogType.Info, "\t\t > {Message}"); - } - else - { - Application.Logger.Log("Failed to load slash command : " + data.PluginName + " because " + data.ErrorMessage, - typeof(PluginMethods), LogType.Error - ); - } - - Console.ForegroundColor = cc; + Application.Logger.Log($"Action {action.ActionName} loaded successfully", LogType.Info); }; - - loader.OnActionLoaded += (data) => + + loader.OnSlashCommandLoaded += (slashCommand) => { - if (data.IsSuccess) - { - Application.Logger.Log("Successfully loaded action : " + data.PluginName, LogType.Info, "\t\t > {Message}"); - } - else - { - Application.Logger.Log("Failed to load action : " + data.PluginName + " because " + data.ErrorMessage, - typeof(PluginMethods), LogType.Error - ); - } - - Console.ForegroundColor = cc; + Application.Logger.Log($"Slash Command {slashCommand.Name} loaded successfully", LogType.Info); }; await loader.LoadPlugins(); - Console.ForegroundColor = cc; return true; } diff --git a/DiscordBot/Program.cs b/DiscordBot/Program.cs index 6dc7d00..073251a 100644 --- a/DiscordBot/Program.cs +++ b/DiscordBot/Program.cs @@ -66,8 +66,8 @@ public class Program { var token = Application.CurrentApplication.ApplicationEnvironmentVariables.Get("token"); var prefix = Application.CurrentApplication.ApplicationEnvironmentVariables.Get("prefix"); - var discordbooter = new App(token, prefix); - await discordbooter.Awake(); + var discordbooter = new DiscordBotApplication(token, prefix); + await discordbooter.StartAsync(); } catch (Exception ex) { diff --git a/DiscordBotCore/Application.cs b/DiscordBotCore/Application.cs index e746e00..c458b72 100644 --- a/DiscordBotCore/Application.cs +++ b/DiscordBotCore/Application.cs @@ -1,10 +1,11 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Diagnostics; -using System.IO; -using System.Threading.Tasks; +using System.IO; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using DiscordBotCore.Bot; using DiscordBotCore.Online; using DiscordBotCore.Online.Helpers; @@ -18,6 +19,7 @@ using DiscordBotCore.Plugin; using DiscordBotCore.Interfaces.PluginManager; using DiscordBotCore.Interfaces.Modules; +using DiscordBotCore.Loaders; namespace DiscordBotCore { @@ -37,29 +39,27 @@ namespace DiscordBotCore private static readonly string _ResourcesFolder = "./Data/Resources"; private static readonly string _PluginsFolder = "./Data/Plugins"; private static readonly string _LogsFolder = "./Data/Logs"; + + private ModuleManager _ModuleManager = null!; + public DiscordBotApplication DiscordBotClient { get; set; } = null!; public List ServerIDs => ApplicationEnvironmentVariables.GetList("ServerID", new List()); public string PluginDatabase => ApplicationEnvironmentVariables.Get("PluginDatabase", _PluginsDatabaseFile); - - private ModuleManager _ModuleManager = null!; - public CustomSettingsDictionary ApplicationEnvironmentVariables { get; private set; } = null!; public InternalActionManager InternalActionManager { get; private set; } = null!; public IPluginManager PluginManager { get; private set; } = null!; - public Bot.App DiscordBotClient { get; internal set; } = null!; + + + public static async Task CreateApplication() { - if (!await OnlineFunctions.IsInternetConnected()) { Console.WriteLine("No internet connection detected. Exiting ..."); Environment.Exit(0); } - if (CurrentApplication is not null) - return; - CurrentApplication = new Application(); Directory.CreateDirectory(_ResourcesFolder); @@ -82,8 +82,7 @@ namespace DiscordBotCore List plugins = new(); await JsonManager.SaveToJsonFile(_PluginsDatabaseFile, plugins); } - - + #if DEBUG CurrentApplication.PluginManager = new PluginManager("tests"); #else @@ -109,8 +108,8 @@ namespace DiscordBotCore /// LogWithTypeAndSender(string message, object sender, LogType type)
/// SetPrintFunction(Action[in string] outFunction)

/// - /// If your custom logger does not have the following methods mapped, the application might crash. - /// Please check modules.json file for the mapping or refer to the official repository for the logger module. + /// If your custom logger does not have the methods from above, the application might crash. + /// Please refer to the official logger documentation for more information. /// public static class Logger { diff --git a/DiscordBotCore/Bot/App.cs b/DiscordBotCore/Bot/DiscordBotApplication.cs similarity index 65% rename from DiscordBotCore/Bot/App.cs rename to DiscordBotCore/Bot/DiscordBotApplication.cs index a349f20..b78021b 100644 --- a/DiscordBotCore/Bot/App.cs +++ b/DiscordBotCore/Bot/DiscordBotApplication.cs @@ -9,17 +9,17 @@ using DiscordBotCore.Others; namespace DiscordBotCore.Bot; -public class App +public class DiscordBotApplication { /// /// The bot prefix /// - public readonly string BotPrefix; + private readonly string _BotPrefix; /// /// The bot token /// - public readonly string BotToken; + private readonly string _BotToken; /// /// The bot client @@ -29,77 +29,67 @@ public class App /// /// The bot command handler /// - private CommandHandler _commandServiceHandler; + private CommandHandler _CommandServiceHandler; /// /// The command service /// - private CommandService _service; + private CommandService _Service; + + /// + /// Checks if the bot is ready + /// + /// true if the bot is ready, otherwise false + private bool IsReady { get; set; } /// /// The main Boot constructor /// /// The bot token /// The bot prefix - public App(string botToken, string botPrefix) + public DiscordBotApplication(string botToken, string botPrefix) { - this.BotPrefix = botPrefix; - this.BotToken = botToken; + this._BotPrefix = botPrefix; + this._BotToken = botToken; } - - /// - /// Checks if the bot is ready - /// - /// true if the bot is ready, otherwise false - public bool IsReady { get; private set; } - /// /// The start method for the bot. This method is used to load the bot /// - /// - /// The discord socket config. If null then the default one will be applied (AlwaysDownloadUsers=true, - /// UseInteractionSnowflakeDate=false, GatewayIntents=GatewayIntents.All) - /// - /// Task - public async Task Awake(DiscordSocketConfig? config = null) + public async Task StartAsync() { - if (config is null) - config = new DiscordSocketConfig - { - AlwaysDownloadUsers = true, + var config = new DiscordSocketConfig + { + AlwaysDownloadUsers = true, - //Disable system clock checkup (for responses at slash commands) - UseInteractionSnowflakeDate = false, - GatewayIntents = GatewayIntents.All - }; + //Disable system clock checkup (for responses at slash commands) + UseInteractionSnowflakeDate = false, + GatewayIntents = GatewayIntents.All + }; Client = new DiscordSocketClient(config); - _service = new CommandService(); - - CommonTasks(); - - await Client.LoginAsync(TokenType.Bot, BotToken); - - await Client.StartAsync(); - - _commandServiceHandler = new CommandHandler(Client, _service, BotPrefix); - - await _commandServiceHandler.InstallCommandsAsync(); - - Application.CurrentApplication.DiscordBotClient = this; - - while (!IsReady) ; - } - - - private void CommonTasks() - { - if (Client == null) return; + _Service = new CommandService(); + Client.Log += Log; Client.LoggedIn += LoggedIn; Client.Ready += Ready; Client.Disconnected += Client_Disconnected; + + await Client.LoginAsync(TokenType.Bot, _BotToken); + + await Client.StartAsync(); + + _CommandServiceHandler = new CommandHandler(Client, _Service, _BotPrefix); + + await _CommandServiceHandler.InstallCommandsAsync(); + + Application.CurrentApplication.DiscordBotClient = this; + + // wait for the bot to be ready + while (!IsReady) + { + await Task.Delay(100); + } } private async Task Client_Disconnected(Exception arg) diff --git a/DiscordBotCore/Loaders/Loader.cs b/DiscordBotCore/Loaders/Loader.cs index 5b14e8e..6c62473 100644 --- a/DiscordBotCore/Loaders/Loader.cs +++ b/DiscordBotCore/Loaders/Loader.cs @@ -1,10 +1,9 @@ using System; -using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; using DiscordBotCore.Interfaces; -using DiscordBotCore.Others; +using DiscordBotCore.Others.Exceptions; namespace DiscordBotCore.Loaders; @@ -13,7 +12,7 @@ internal class Loader internal delegate void FileLoadedHandler(FileLoaderResult result); - internal delegate void PluginLoadedHandler(PluginLoadResultData result); + internal delegate void PluginLoadedHandler(PluginLoaderResult result); internal event FileLoadedHandler? OnFileLoadedException; internal event PluginLoadedHandler? OnPluginLoaded; @@ -21,8 +20,8 @@ internal class Loader internal async Task Load() { var installedPlugins = await Application.CurrentApplication.PluginManager.GetInstalledPlugins(); - var files = installedPlugins.Where(plugin=>plugin.IsEnabled).Select(plugin => plugin.FilePath).ToArray(); - + var files = installedPlugins.Where(plugin => plugin.IsEnabled).Select(plugin => plugin.FilePath).ToArray(); + foreach (var file in files) { try @@ -41,7 +40,7 @@ internal class Loader await LoadEverythingOfType(); } - private async Task LoadEverythingOfType() + private Task LoadEverythingOfType() { var types = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(s => s.GetTypes()) @@ -58,25 +57,24 @@ internal class Loader throw new Exception($"Failed to create instance of plugin with type {type.FullName} [{type.Assembly}]"); } - var pluginType = plugin switch + PluginLoaderResult result = plugin switch { - IDbEvent => PluginType.EVENT, - IDbCommand => PluginType.COMMAND, - IDbSlashCommand => PluginType.SLASH_COMMAND, - ICommandAction => PluginType.ACTION, - _ => PluginType.UNKNOWN + IDbEvent @event => PluginLoaderResult.FromIDbEvent(@event), + IDbCommand command => PluginLoaderResult.FromIDbCommand(command), + IDbSlashCommand command => PluginLoaderResult.FromIDbSlashCommand(command), + ICommandAction action => PluginLoaderResult.FromICommandAction(action), + _ => PluginLoaderResult.FromException(new PluginNotFoundException($"Unknown plugin type {plugin.GetType().FullName}")) }; - if (pluginType == PluginType.UNKNOWN) - throw new Exception($"Unknown plugin type for plugin with type {type.FullName} [{type.Assembly}]"); - - OnPluginLoaded?.Invoke(new PluginLoadResultData(type.FullName, pluginType, true, plugin: plugin)); + OnPluginLoaded?.Invoke(result); } catch (Exception ex) { - OnPluginLoaded?.Invoke(new PluginLoadResultData(type.FullName, PluginType.UNKNOWN, false, ex.Message)); + OnPluginLoaded?.Invoke(PluginLoaderResult.FromException(ex)); } } + + return Task.CompletedTask; } } diff --git a/DiscordBotCore/Loaders/PluginLoadResultData.cs b/DiscordBotCore/Loaders/PluginLoadResultData.cs deleted file mode 100644 index ba02086..0000000 --- a/DiscordBotCore/Loaders/PluginLoadResultData.cs +++ /dev/null @@ -1,23 +0,0 @@ -using DiscordBotCore.Others; - -namespace DiscordBotCore.Loaders; - -public class PluginLoadResultData -{ - public string PluginName { get; init; } - public PluginType PluginType { get; init; } - public string? ErrorMessage { get; init; } - public bool IsSuccess { get; init; } - - public object Plugin { get; init; } - - public PluginLoadResultData(string pluginName, PluginType pluginType, bool isSuccess, string? errorMessage = null, - object? plugin = null) - { - PluginName = pluginName; - PluginType = pluginType; - IsSuccess = isSuccess; - ErrorMessage = errorMessage; - Plugin = plugin is null ? new() : plugin; - } -} diff --git a/DiscordBotCore/Loaders/PluginLoader.cs b/DiscordBotCore/Loaders/PluginLoader.cs index 2511fbb..fef6bd0 100644 --- a/DiscordBotCore/Loaders/PluginLoader.cs +++ b/DiscordBotCore/Loaders/PluginLoader.cs @@ -1,25 +1,21 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Threading.Tasks; using Discord.WebSocket; using DiscordBotCore.Interfaces; using DiscordBotCore.Others; +using DiscordBotCore.Others.Exceptions; namespace DiscordBotCore.Loaders; -public class PluginLoader +public sealed class PluginLoader { - internal readonly DiscordSocketClient _Client; - - public delegate void CommandLoaded(PluginLoadResultData resultData); - - public delegate void EventLoaded(PluginLoadResultData resultData); - - public delegate void SlashCommandLoaded(PluginLoadResultData resultData); - - public delegate void ActionLoaded(PluginLoadResultData resultData); + private readonly DiscordSocketClient _Client; + public delegate void CommandLoaded(IDbCommand eCommand); + public delegate void EventLoaded(IDbEvent eEvent); + public delegate void SlashCommandLoaded(IDbSlashCommand eSlashCommand); + public delegate void ActionLoaded(ICommandAction eAction); public CommandLoaded? OnCommandLoaded; public EventLoaded? OnEventLoaded; @@ -38,13 +34,6 @@ public class PluginLoader public async Task LoadPlugins() { - - if (_Client == null) - { - Application.Logger.Log("Discord client is null", this, LogType.Error); - return; - } - Commands.Clear(); Events.Clear(); SlashCommands.Clear(); @@ -65,48 +54,62 @@ public class PluginLoader Application.Logger.Log(result.ErrorMessage, this, LogType.Error); } - private async void OnPluginLoaded(PluginLoadResultData result) + private async void InitializeCommand(ICommandAction action) { - switch (result.PluginType) + if (action.RunType == InternalActionRunType.OnStartup || action.RunType == InternalActionRunType.OnStartupAndCall) + await Application.CurrentApplication.InternalActionManager.StartAction(action, null); + + if(action.RunType == InternalActionRunType.OnCall || action.RunType == InternalActionRunType.OnStartupAndCall) + Actions.Add(action); + + OnActionLoaded?.Invoke(action); + } + + private void InitializeDbCommand(IDbCommand command) + { + Commands.Add(command); + OnCommandLoaded?.Invoke(command); + } + + private void InitializeEvent(IDbEvent eEvent) + { + if (!eEvent.TryStartEvent()) { - case PluginType.ACTION: - ICommandAction action = (ICommandAction)result.Plugin; - if (action.RunType == InternalActionRunType.OnStartup || action.RunType == InternalActionRunType.OnStartupAndCall) - await Application.CurrentApplication.InternalActionManager.StartAction(action, null); - - if(action.RunType == InternalActionRunType.OnCall || action.RunType == InternalActionRunType.OnStartupAndCall) - Actions.Add(action); - - OnActionLoaded?.Invoke(result); - - break; - case PluginType.COMMAND: - Commands.Add((IDbCommand)result.Plugin); - OnCommandLoaded?.Invoke(result); - break; - case PluginType.EVENT: - if (this.TryStartEvent((IDbEvent)result.Plugin)) - { - Events.Add((IDbEvent)result.Plugin); - OnEventLoaded?.Invoke(result); - } - - break; - case PluginType.SLASH_COMMAND: - if (await this.TryStartSlashCommand((IDbSlashCommand)result.Plugin)) - { - if(((IDbSlashCommand)result.Plugin).HasInteraction) - _Client.InteractionCreated += ((IDbSlashCommand)result.Plugin).ExecuteInteraction; - SlashCommands.Add((IDbSlashCommand)result.Plugin); - OnSlashCommandLoaded?.Invoke(result); - } - else - Application.Logger.Log($"Failed to start slash command {result.PluginName}", this, LogType.Error); - break; - case PluginType.UNKNOWN: - default: - Application.Logger.Log("Unknown plugin type", this, LogType.Error); - break; + return; } + + Events.Add(eEvent); + OnEventLoaded?.Invoke(eEvent); + } + + private async void InitializeSlashCommand(IDbSlashCommand slashCommand) + { + Result result = await slashCommand.TryStartSlashCommand(); + result.Match( + () => + { + if (slashCommand.HasInteraction) + _Client.InteractionCreated += slashCommand.ExecuteInteraction; + SlashCommands.Add(slashCommand); + OnSlashCommandLoaded?.Invoke(slashCommand); + }, + HandleError + ); + } + + private void HandleError(Exception exception) + { + Application.Logger.Log(exception.Message, this, LogType.Error); + } + + private void OnPluginLoaded(PluginLoaderResult result) + { + result.Match( + InitializeDbCommand, + InitializeEvent, + InitializeSlashCommand, + InitializeCommand, + HandleError + ); } } diff --git a/DiscordBotCore/Loaders/PluginLoaderExtensions.cs b/DiscordBotCore/Loaders/PluginLoaderExtensions.cs index 6adde1b..c91dc7b 100644 --- a/DiscordBotCore/Loaders/PluginLoaderExtensions.cs +++ b/DiscordBotCore/Loaders/PluginLoaderExtensions.cs @@ -14,7 +14,7 @@ namespace DiscordBotCore.Loaders; internal static class PluginLoaderExtensions { - internal static bool TryStartEvent(this PluginLoader pluginLoader, IDbEvent? dbEvent) + internal static bool TryStartEvent(this IDbEvent? dbEvent) { try { @@ -23,7 +23,7 @@ internal static class PluginLoaderExtensions throw new ArgumentNullException(nameof(dbEvent)); } - dbEvent.Start(pluginLoader._Client); + dbEvent.Start(Application.CurrentApplication.DiscordBotClient.Client); return true; } catch (Exception e) @@ -34,18 +34,18 @@ internal static class PluginLoaderExtensions } } - internal static async Task TryStartSlashCommand(this PluginLoader pluginLoader, IDbSlashCommand? dbSlashCommand) + internal static async Task TryStartSlashCommand(this IDbSlashCommand? dbSlashCommand) { try { if (dbSlashCommand is null) { - return false; + return Result.Failure(new Exception("dbSlashCommand is null")); } - if (pluginLoader._Client.Guilds.Count == 0) + if (Application.CurrentApplication.DiscordBotClient.Client.Guilds.Count == 0) { - return false; + return Result.Failure(new Exception("No guilds found")); } var builder = new SlashCommandBuilder(); @@ -60,28 +60,27 @@ internal static class PluginLoaderExtensions foreach(ulong guildId in Application.CurrentApplication.ServerIDs) { - bool result = await pluginLoader.EnableSlashCommandPerGuild(guildId, builder); + bool result = await EnableSlashCommandPerGuild(guildId, builder); if (!result) { - Application.Logger.Log($"Failed to enable slash command {dbSlashCommand.Name} for guild {guildId}", typeof(PluginLoader), LogType.Error); + return Result.Failure($"Failed to enable slash command {dbSlashCommand.Name} for guild {guildId}"); } } - await pluginLoader._Client.CreateGlobalApplicationCommandAsync(builder.Build()); + await Application.CurrentApplication.DiscordBotClient.Client.CreateGlobalApplicationCommandAsync(builder.Build()); - return true; + return Result.Success(); } catch (Exception e) { - Application.Logger.Log($"Error starting slash command {dbSlashCommand.Name}: {e.Message}", typeof(PluginLoader), LogType.Error); - return false; + return Result.Failure("Error starting slash command"); } } - private static async Task EnableSlashCommandPerGuild(this PluginLoader pluginLoader, ulong guildId, SlashCommandBuilder builder) + private static async Task EnableSlashCommandPerGuild(ulong guildId, SlashCommandBuilder builder) { - SocketGuild? guild = pluginLoader._Client.GetGuild(guildId); + SocketGuild? guild = Application.CurrentApplication.DiscordBotClient.Client.GetGuild(guildId); if (guild is null) { Application.Logger.Log("Failed to get guild with ID " + guildId, typeof(PluginLoader), LogType.Error); diff --git a/DiscordBotCore/Loaders/PluginLoaderResult.cs b/DiscordBotCore/Loaders/PluginLoaderResult.cs new file mode 100644 index 0000000..aad5689 --- /dev/null +++ b/DiscordBotCore/Loaders/PluginLoaderResult.cs @@ -0,0 +1,42 @@ +using System; +using DiscordBotCore.Interfaces; +using DiscordBotCore.Others; +using DiscordBotCore.Others.Exceptions; + +namespace DiscordBotCore.Loaders; + + +public class PluginLoaderResult +{ + private Option4 _Result; + + public static PluginLoaderResult FromIDbCommand(IDbCommand command) => new PluginLoaderResult(new Option4(command)); + + public static PluginLoaderResult FromIDbEvent(IDbEvent dbEvent) => new PluginLoaderResult(new Option4(dbEvent)); + + public static PluginLoaderResult FromIDbSlashCommand(IDbSlashCommand slashCommand) => new PluginLoaderResult(new Option4(slashCommand)); + + public static PluginLoaderResult FromICommandAction(ICommandAction commandAction) => new PluginLoaderResult(new Option4(commandAction)); + + public static PluginLoaderResult FromException(Exception exception) => new PluginLoaderResult(new Option4(exception)); + public static PluginLoaderResult FromException(string exception) => new PluginLoaderResult(new Option4(new Exception(message: exception))); + + private PluginLoaderResult(Option4 result) + { + _Result = result; + } + + public void Match(Action commandAction, Action eventAction, Action slashCommandAction, + Action commandActionAction, Action exceptionAction) + { + _Result.Match(commandAction, eventAction, slashCommandAction, commandActionAction, exceptionAction); + } + + public TResult Match(Func commandFunc, Func eventFunc, + Func slashCommandFunc, Func commandActionFunc, + Func exceptionFunc) + { + return _Result.Match(commandFunc, eventFunc, slashCommandFunc, commandActionFunc, exceptionFunc); + } + +} \ No newline at end of file diff --git a/DiscordBotCore/Modules/ModuleManager.cs b/DiscordBotCore/Modules/ModuleManager.cs index 2155877..dd3e241 100644 --- a/DiscordBotCore/Modules/ModuleManager.cs +++ b/DiscordBotCore/Modules/ModuleManager.cs @@ -135,9 +135,9 @@ namespace DiscordBotCore.Modules var availableModules = await GetAllModules(module); Console.WriteLine("Please select a module of type " + module); - for (int i = 0; i < availableModules.Count; i++) + for (var i = 0; i < availableModules.Count; i++) { - Console.WriteLine(i + " - " + availableModules[i].ModuleName); + Console.WriteLine((i+1) + " - " + availableModules[i].ModuleName); Console.WriteLine("Author: " + availableModules[i].ModuleAuthor); Console.WriteLine("Description: " + availableModules[i].ModuleDescription); diff --git a/DiscordBotCore/Others/DBCommandExecutingArguments.cs b/DiscordBotCore/Others/DBCommandExecutingArguments.cs index d2c9647..5ba2939 100644 --- a/DiscordBotCore/Others/DBCommandExecutingArguments.cs +++ b/DiscordBotCore/Others/DBCommandExecutingArguments.cs @@ -33,7 +33,8 @@ public class DbCommandExecutingArguments } else { - CleanContent = message.Content.Substring(Application.CurrentApplication.DiscordBotClient.BotPrefix.Length); + string? prefix = Application.CurrentApplication.ApplicationEnvironmentVariables.Get("prefix"); + CleanContent = message.Content.Substring(prefix?.Length ?? 0); } var split = CleanContent.Split(' '); diff --git a/DiscordBotCore/Others/Exceptions/PluginNotFoundException.cs b/DiscordBotCore/Others/Exceptions/PluginNotFoundException.cs index 39dd1ba..cf0ed69 100644 --- a/DiscordBotCore/Others/Exceptions/PluginNotFoundException.cs +++ b/DiscordBotCore/Others/Exceptions/PluginNotFoundException.cs @@ -2,7 +2,7 @@ namespace DiscordBotCore.Others.Exceptions { - internal class PluginNotFoundException : Exception + public class PluginNotFoundException : Exception { public PluginNotFoundException(string pluginName) : base($"Plugin {pluginName} was not found") { } diff --git a/DiscordBotCore/Others/OneOf.cs b/DiscordBotCore/Others/OneOf.cs index ef5abe5..b84abb5 100644 --- a/DiscordBotCore/Others/OneOf.cs +++ b/DiscordBotCore/Others/OneOf.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace DiscordBotCore.Others { @@ -132,4 +132,4 @@ namespace DiscordBotCore.Others } } -} +} \ No newline at end of file diff --git a/DiscordBotCore/Others/Option.cs b/DiscordBotCore/Others/Option.cs new file mode 100644 index 0000000..cd35751 --- /dev/null +++ b/DiscordBotCore/Others/Option.cs @@ -0,0 +1,179 @@ +using System; + +namespace DiscordBotCore.Others; + + +public class Option2 where TError : Exception +{ + private readonly int _Index; + + private T0 Item0 { get; } = default!; + private T1 Item1 { get; } = default!; + + private TError Error { get; } = default!; + + private Option2(T0 item0) + { + Item0 = item0; + _Index = 0; + } + + private Option2(T1 item1) + { + Item1 = item1; + _Index = 1; + } + + private Option2(TError error) + { + Error = error; + _Index = 2; + } + + public static implicit operator Option2(T0 item0) => new Option2(item0); + public static implicit operator Option2(T1 item1) => new Option2(item1); + public static implicit operator Option2(TError error) => new Option2(error); + + public void Match(Action item0, Action item1, Action error) + { + switch (_Index) + { + case 0: + item0(Item0); + break; + case 1: + item1(Item1); + break; + case 2: + error(Error); + break; + default: + throw new InvalidOperationException(); + } + } + + public TResult Match(Func item0, Func item1, Func error) + { + return _Index switch + { + 0 => item0(Item0), + 1 => item1(Item1), + 2 => error(Error), + _ => throw new InvalidOperationException(), + }; + } + + public override string ToString() + { + return _Index switch + { + 0 => $"Option2<{typeof(T0).Name}>: {Item0}", + 1 => $"Option2<{typeof(T1).Name}>: {Item1}", + 2 => $"Option2<{typeof(TError).Name}>: {Error}", + _ => "Invalid Option2" + }; + } + +} + +public class Option4 where TError : Exception +{ + private readonly int _Index; + + private T0 Item0 { get; } = default!; + private T1 Item1 { get; } = default!; + private T2 Item2 { get; } = default!; + private T3 Item3 { get; } = default!; + + private TError Error { get; } = default!; + + internal Option4(T0 item0) + { + Item0 = item0; + _Index = 0; + } + + internal Option4(T1 item1) + { + Item1 = item1; + _Index = 1; + } + + internal Option4(T2 item2) + { + Item2 = item2; + _Index = 2; + } + + internal Option4(T3 item3) + { + Item3 = item3; + _Index = 3; + } + + internal Option4(TError error) + { + Error = error; + _Index = 4; + } + + + public static implicit operator Option4(T0 item0) => new Option4(item0); + public static implicit operator Option4(T1 item1) => new Option4(item1); + public static implicit operator Option4(T2 item2) => new Option4(item2); + public static implicit operator Option4(T3 item3) => new Option4(item3); + public static implicit operator Option4(TError error) => new Option4(error); + + + public void Match(Action item0, Action item1, Action item2, Action item3, Action error) + { + switch (_Index) + { + case 0: + item0(Item0); + break; + case 1: + item1(Item1); + break; + case 2: + item2(Item2); + break; + case 3: + item3(Item3); + break; + case 4: + error(Error); + break; + default: + throw new InvalidOperationException(); + } + } + + + public TResult Match(Func item0, Func item1, Func item2, Func item3, Func error) + { + return _Index switch + { + 0 => item0(Item0), + 1 => item1(Item1), + 2 => item2(Item2), + 3 => item3(Item3), + 4 => error(Error), + _ => throw new InvalidOperationException(), + }; + } + + public override string ToString() + { + return _Index switch + { + 0 => $"Option4<{typeof(T0).Name}>: {Item0}", + 1 => $"Option4<{typeof(T1).Name}>: {Item1}", + 2 => $"Option4<{typeof(T2).Name}>: {Item2}", + 3 => $"Option4<{typeof(T3).Name}>: {Item3}", + 4 => $"Option4<{typeof(TError).Name}>: {Error}", + _ => "Invalid Option4" + }; + } +} + diff --git a/DiscordBotCore/Others/Result.cs b/DiscordBotCore/Others/Result.cs new file mode 100644 index 0000000..7e94b09 --- /dev/null +++ b/DiscordBotCore/Others/Result.cs @@ -0,0 +1,64 @@ +using System; + +namespace DiscordBotCore.Others; + +public class Result +{ + private bool? _Result; + private Exception? Exception { get; } + + + private Result(Exception exception) + { + _Result = null; + Exception = exception; + } + + private Result(bool result) + { + _Result = result; + Exception = null; + } + + public static Result Success() => new Result(true); + public static Result Failure(Exception ex) => new Result(ex); + public static Result Failure(string message) => new Result(new Exception(message)); + + public void Match(Action successAction, Action exceptionAction) + { + if (_Result.HasValue && _Result.Value) + { + successAction(); + } + else + { + exceptionAction(Exception!); + } + } + +} + +public class Result +{ + private readonly OneOf _Result; + + private Result(OneOf result) + { + _Result = result; + } + + public static Result From (T value) => new Result(new OneOf(value)); + public static implicit operator Result(Exception exception) => new Result(new OneOf(exception)); + + + + public void Match(Action valueAction, Action exceptionAction) + { + _Result.Match(valueAction, exceptionAction); + } + + public TResult Match(Func valueFunc, Func exceptionFunc) + { + return _Result.Match(valueFunc, exceptionFunc); + } +} diff --git a/DiscordBotCore/Others/Settings/CustomSettingsDictionary.cs b/DiscordBotCore/Others/Settings/CustomSettingsDictionary.cs index 32a5791..0ed9275 100644 --- a/DiscordBotCore/Others/Settings/CustomSettingsDictionary.cs +++ b/DiscordBotCore/Others/Settings/CustomSettingsDictionary.cs @@ -49,8 +49,21 @@ public class CustomSettingsDictionary : CustomSettingsDictionaryBase(jsonContent); + + if (jObject is null) + { + await SaveToFile(); + return; + } + _InternalDictionary.Clear(); foreach (var kvp in jObject)