Updated performance in plugin loading
This commit is contained in:
@@ -211,79 +211,33 @@ internal static class PluginMethods
|
|||||||
internal static async Task<bool> LoadPlugins(string[] args)
|
internal static async Task<bool> LoadPlugins(string[] args)
|
||||||
{
|
{
|
||||||
var loader = new PluginLoader(Application.CurrentApplication.DiscordBotClient.Client);
|
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();
|
await loader.LoadPlugins();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cc = Console.ForegroundColor;
|
loader.OnCommandLoaded += (command) =>
|
||||||
loader.OnCommandLoaded += (data) =>
|
|
||||||
{
|
{
|
||||||
if (data.IsSuccess)
|
Application.Logger.Log($"Command {command.Command} loaded successfully", LogType.Info);
|
||||||
{
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
loader.OnEventLoaded += (data) =>
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
loader.OnSlashCommandLoaded += (data) =>
|
loader.OnEventLoaded += (eEvent) =>
|
||||||
{
|
{
|
||||||
if (data.IsSuccess)
|
Application.Logger.Log($"Event {eEvent.Name} loaded successfully",LogType.Info);
|
||||||
{
|
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
loader.OnActionLoaded += (data) =>
|
loader.OnActionLoaded += (action) =>
|
||||||
{
|
{
|
||||||
if (data.IsSuccess)
|
Application.Logger.Log($"Action {action.ActionName} loaded successfully", LogType.Info);
|
||||||
{
|
};
|
||||||
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;
|
loader.OnSlashCommandLoaded += (slashCommand) =>
|
||||||
|
{
|
||||||
|
Application.Logger.Log($"Slash Command {slashCommand.Name} loaded successfully", LogType.Info);
|
||||||
};
|
};
|
||||||
|
|
||||||
await loader.LoadPlugins();
|
await loader.LoadPlugins();
|
||||||
Console.ForegroundColor = cc;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ public class Program
|
|||||||
{
|
{
|
||||||
var token = Application.CurrentApplication.ApplicationEnvironmentVariables.Get<string>("token");
|
var token = Application.CurrentApplication.ApplicationEnvironmentVariables.Get<string>("token");
|
||||||
var prefix = Application.CurrentApplication.ApplicationEnvironmentVariables.Get<string>("prefix");
|
var prefix = Application.CurrentApplication.ApplicationEnvironmentVariables.Get<string>("prefix");
|
||||||
var discordbooter = new App(token, prefix);
|
var discordbooter = new DiscordBotApplication(token, prefix);
|
||||||
await discordbooter.Awake();
|
await discordbooter.StartAsync();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
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;
|
||||||
using DiscordBotCore.Online.Helpers;
|
using DiscordBotCore.Online.Helpers;
|
||||||
|
|
||||||
@@ -18,6 +19,7 @@ using DiscordBotCore.Plugin;
|
|||||||
|
|
||||||
using DiscordBotCore.Interfaces.PluginManager;
|
using DiscordBotCore.Interfaces.PluginManager;
|
||||||
using DiscordBotCore.Interfaces.Modules;
|
using DiscordBotCore.Interfaces.Modules;
|
||||||
|
using DiscordBotCore.Loaders;
|
||||||
|
|
||||||
namespace DiscordBotCore
|
namespace DiscordBotCore
|
||||||
{
|
{
|
||||||
@@ -38,28 +40,26 @@ namespace DiscordBotCore
|
|||||||
private static readonly string _PluginsFolder = "./Data/Plugins";
|
private static readonly string _PluginsFolder = "./Data/Plugins";
|
||||||
private static readonly string _LogsFolder = "./Data/Logs";
|
private static readonly string _LogsFolder = "./Data/Logs";
|
||||||
|
|
||||||
|
private ModuleManager _ModuleManager = null!;
|
||||||
|
public DiscordBotApplication DiscordBotClient { get; set; } = null!;
|
||||||
|
|
||||||
public List<ulong> ServerIDs => ApplicationEnvironmentVariables.GetList("ServerID", new List<ulong>());
|
public List<ulong> ServerIDs => ApplicationEnvironmentVariables.GetList("ServerID", new List<ulong>());
|
||||||
public string PluginDatabase => ApplicationEnvironmentVariables.Get<string>("PluginDatabase", _PluginsDatabaseFile);
|
public string PluginDatabase => ApplicationEnvironmentVariables.Get<string>("PluginDatabase", _PluginsDatabaseFile);
|
||||||
|
|
||||||
private ModuleManager _ModuleManager = null!;
|
|
||||||
|
|
||||||
public CustomSettingsDictionary ApplicationEnvironmentVariables { get; private set; } = null!;
|
public CustomSettingsDictionary ApplicationEnvironmentVariables { get; private set; } = null!;
|
||||||
public InternalActionManager InternalActionManager { get; private set; } = null!;
|
public InternalActionManager InternalActionManager { get; private set; } = null!;
|
||||||
public IPluginManager PluginManager { get; private set; } = null!;
|
public IPluginManager PluginManager { get; private set; } = null!;
|
||||||
public Bot.App DiscordBotClient { get; internal set; } = null!;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static async Task CreateApplication()
|
public static async Task CreateApplication()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!await OnlineFunctions.IsInternetConnected())
|
if (!await OnlineFunctions.IsInternetConnected())
|
||||||
{
|
{
|
||||||
Console.WriteLine("No internet connection detected. Exiting ...");
|
Console.WriteLine("No internet connection detected. Exiting ...");
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CurrentApplication is not null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CurrentApplication = new Application();
|
CurrentApplication = new Application();
|
||||||
|
|
||||||
Directory.CreateDirectory(_ResourcesFolder);
|
Directory.CreateDirectory(_ResourcesFolder);
|
||||||
@@ -83,7 +83,6 @@ namespace DiscordBotCore
|
|||||||
await JsonManager.SaveToJsonFile(_PluginsDatabaseFile, plugins);
|
await JsonManager.SaveToJsonFile(_PluginsDatabaseFile, plugins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
CurrentApplication.PluginManager = new PluginManager("tests");
|
CurrentApplication.PluginManager = new PluginManager("tests");
|
||||||
#else
|
#else
|
||||||
@@ -109,8 +108,8 @@ namespace DiscordBotCore
|
|||||||
/// LogWithTypeAndSender(string message, object sender, LogType type)<br/>
|
/// LogWithTypeAndSender(string message, object sender, LogType type)<br/>
|
||||||
/// SetPrintFunction(Action[in string] outFunction)<br/><br/>
|
/// SetPrintFunction(Action[in string] outFunction)<br/><br/>
|
||||||
///
|
///
|
||||||
/// If your custom logger does not have the following methods mapped, the application might crash.
|
/// If your custom logger does not have the methods from above, the application might crash.
|
||||||
/// Please check <b>modules.json</b> file for the mapping or refer to the official repository for the logger module.
|
/// Please refer to the official logger documentation for more information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class Logger
|
public static class Logger
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,17 +9,17 @@ using DiscordBotCore.Others;
|
|||||||
|
|
||||||
namespace DiscordBotCore.Bot;
|
namespace DiscordBotCore.Bot;
|
||||||
|
|
||||||
public class App
|
public class DiscordBotApplication
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The bot prefix
|
/// The bot prefix
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly string BotPrefix;
|
private readonly string _BotPrefix;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The bot token
|
/// The bot token
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly string BotToken;
|
private readonly string _BotToken;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The bot client
|
/// The bot client
|
||||||
@@ -29,77 +29,67 @@ public class App
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The bot command handler
|
/// The bot command handler
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private CommandHandler _commandServiceHandler;
|
private CommandHandler _CommandServiceHandler;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The command service
|
/// The command service
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private CommandService _service;
|
private CommandService _Service;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the bot is ready
|
||||||
|
/// </summary>
|
||||||
|
/// <value> true if the bot is ready, otherwise false </value>
|
||||||
|
private bool IsReady { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The main Boot constructor
|
/// The main Boot constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="botToken">The bot token</param>
|
/// <param name="botToken">The bot token</param>
|
||||||
/// <param name="botPrefix">The bot prefix</param>
|
/// <param name="botPrefix">The bot prefix</param>
|
||||||
public App(string botToken, string botPrefix)
|
public DiscordBotApplication(string botToken, string botPrefix)
|
||||||
{
|
{
|
||||||
this.BotPrefix = botPrefix;
|
this._BotPrefix = botPrefix;
|
||||||
this.BotToken = botToken;
|
this._BotToken = botToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the bot is ready
|
|
||||||
/// </summary>
|
|
||||||
/// <value> true if the bot is ready, otherwise false </value>
|
|
||||||
public bool IsReady { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The start method for the bot. This method is used to load the bot
|
/// The start method for the bot. This method is used to load the bot
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="config">
|
public async Task StartAsync()
|
||||||
/// The discord socket config. If null then the default one will be applied (AlwaysDownloadUsers=true,
|
|
||||||
/// UseInteractionSnowflakeDate=false, GatewayIntents=GatewayIntents.All)
|
|
||||||
/// </param>
|
|
||||||
/// <returns>Task</returns>
|
|
||||||
public async Task Awake(DiscordSocketConfig? config = null)
|
|
||||||
{
|
{
|
||||||
if (config is null)
|
var config = new DiscordSocketConfig
|
||||||
config = new DiscordSocketConfig
|
{
|
||||||
{
|
AlwaysDownloadUsers = true,
|
||||||
AlwaysDownloadUsers = true,
|
|
||||||
|
|
||||||
//Disable system clock checkup (for responses at slash commands)
|
//Disable system clock checkup (for responses at slash commands)
|
||||||
UseInteractionSnowflakeDate = false,
|
UseInteractionSnowflakeDate = false,
|
||||||
GatewayIntents = GatewayIntents.All
|
GatewayIntents = GatewayIntents.All
|
||||||
};
|
};
|
||||||
|
|
||||||
Client = new DiscordSocketClient(config);
|
Client = new DiscordSocketClient(config);
|
||||||
_service = new CommandService();
|
_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;
|
|
||||||
Client.Log += Log;
|
Client.Log += Log;
|
||||||
Client.LoggedIn += LoggedIn;
|
Client.LoggedIn += LoggedIn;
|
||||||
Client.Ready += Ready;
|
Client.Ready += Ready;
|
||||||
Client.Disconnected += Client_Disconnected;
|
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)
|
private async Task Client_Disconnected(Exception arg)
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using DiscordBotCore.Interfaces;
|
using DiscordBotCore.Interfaces;
|
||||||
using DiscordBotCore.Others;
|
using DiscordBotCore.Others.Exceptions;
|
||||||
|
|
||||||
namespace DiscordBotCore.Loaders;
|
namespace DiscordBotCore.Loaders;
|
||||||
|
|
||||||
@@ -13,7 +12,7 @@ internal class Loader
|
|||||||
|
|
||||||
internal delegate void FileLoadedHandler(FileLoaderResult result);
|
internal delegate void FileLoadedHandler(FileLoaderResult result);
|
||||||
|
|
||||||
internal delegate void PluginLoadedHandler(PluginLoadResultData result);
|
internal delegate void PluginLoadedHandler(PluginLoaderResult result);
|
||||||
|
|
||||||
internal event FileLoadedHandler? OnFileLoadedException;
|
internal event FileLoadedHandler? OnFileLoadedException;
|
||||||
internal event PluginLoadedHandler? OnPluginLoaded;
|
internal event PluginLoadedHandler? OnPluginLoaded;
|
||||||
@@ -21,7 +20,7 @@ internal class Loader
|
|||||||
internal async Task Load()
|
internal async Task Load()
|
||||||
{
|
{
|
||||||
var installedPlugins = await Application.CurrentApplication.PluginManager.GetInstalledPlugins();
|
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)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
@@ -41,7 +40,7 @@ internal class Loader
|
|||||||
await LoadEverythingOfType<ICommandAction>();
|
await LoadEverythingOfType<ICommandAction>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoadEverythingOfType<T>()
|
private Task LoadEverythingOfType<T>()
|
||||||
{
|
{
|
||||||
var types = AppDomain.CurrentDomain.GetAssemblies()
|
var types = AppDomain.CurrentDomain.GetAssemblies()
|
||||||
.SelectMany(s => s.GetTypes())
|
.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}]");
|
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,
|
IDbEvent @event => PluginLoaderResult.FromIDbEvent(@event),
|
||||||
IDbCommand => PluginType.COMMAND,
|
IDbCommand command => PluginLoaderResult.FromIDbCommand(command),
|
||||||
IDbSlashCommand => PluginType.SLASH_COMMAND,
|
IDbSlashCommand command => PluginLoaderResult.FromIDbSlashCommand(command),
|
||||||
ICommandAction => PluginType.ACTION,
|
ICommandAction action => PluginLoaderResult.FromICommandAction(action),
|
||||||
_ => PluginType.UNKNOWN
|
_ => PluginLoaderResult.FromException(new PluginNotFoundException($"Unknown plugin type {plugin.GetType().FullName}"))
|
||||||
};
|
};
|
||||||
|
|
||||||
if (pluginType == PluginType.UNKNOWN)
|
OnPluginLoaded?.Invoke(result);
|
||||||
throw new Exception($"Unknown plugin type for plugin with type {type.FullName} [{type.Assembly}]");
|
|
||||||
|
|
||||||
OnPluginLoaded?.Invoke(new PluginLoadResultData(type.FullName, pluginType, true, plugin: plugin));
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
OnPluginLoaded?.Invoke(new PluginLoadResultData(type.FullName, PluginType.UNKNOWN, false, ex.Message));
|
OnPluginLoaded?.Invoke(PluginLoaderResult.FromException(ex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +1,21 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using DiscordBotCore.Interfaces;
|
using DiscordBotCore.Interfaces;
|
||||||
using DiscordBotCore.Others;
|
using DiscordBotCore.Others;
|
||||||
|
using DiscordBotCore.Others.Exceptions;
|
||||||
|
|
||||||
|
|
||||||
namespace DiscordBotCore.Loaders;
|
namespace DiscordBotCore.Loaders;
|
||||||
|
|
||||||
public class PluginLoader
|
public sealed class PluginLoader
|
||||||
{
|
{
|
||||||
internal readonly DiscordSocketClient _Client;
|
private readonly DiscordSocketClient _Client;
|
||||||
|
public delegate void CommandLoaded(IDbCommand eCommand);
|
||||||
public delegate void CommandLoaded(PluginLoadResultData resultData);
|
public delegate void EventLoaded(IDbEvent eEvent);
|
||||||
|
public delegate void SlashCommandLoaded(IDbSlashCommand eSlashCommand);
|
||||||
public delegate void EventLoaded(PluginLoadResultData resultData);
|
public delegate void ActionLoaded(ICommandAction eAction);
|
||||||
|
|
||||||
public delegate void SlashCommandLoaded(PluginLoadResultData resultData);
|
|
||||||
|
|
||||||
public delegate void ActionLoaded(PluginLoadResultData resultData);
|
|
||||||
|
|
||||||
public CommandLoaded? OnCommandLoaded;
|
public CommandLoaded? OnCommandLoaded;
|
||||||
public EventLoaded? OnEventLoaded;
|
public EventLoaded? OnEventLoaded;
|
||||||
@@ -38,13 +34,6 @@ public class PluginLoader
|
|||||||
|
|
||||||
public async Task LoadPlugins()
|
public async Task LoadPlugins()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (_Client == null)
|
|
||||||
{
|
|
||||||
Application.Logger.Log("Discord client is null", this, LogType.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Commands.Clear();
|
Commands.Clear();
|
||||||
Events.Clear();
|
Events.Clear();
|
||||||
SlashCommands.Clear();
|
SlashCommands.Clear();
|
||||||
@@ -65,48 +54,62 @@ public class PluginLoader
|
|||||||
Application.Logger.Log(result.ErrorMessage, this, LogType.Error);
|
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:
|
return;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace DiscordBotCore.Loaders;
|
|||||||
|
|
||||||
internal static class PluginLoaderExtensions
|
internal static class PluginLoaderExtensions
|
||||||
{
|
{
|
||||||
internal static bool TryStartEvent(this PluginLoader pluginLoader, IDbEvent? dbEvent)
|
internal static bool TryStartEvent(this IDbEvent? dbEvent)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -23,7 +23,7 @@ internal static class PluginLoaderExtensions
|
|||||||
throw new ArgumentNullException(nameof(dbEvent));
|
throw new ArgumentNullException(nameof(dbEvent));
|
||||||
}
|
}
|
||||||
|
|
||||||
dbEvent.Start(pluginLoader._Client);
|
dbEvent.Start(Application.CurrentApplication.DiscordBotClient.Client);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -34,18 +34,18 @@ internal static class PluginLoaderExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<bool> TryStartSlashCommand(this PluginLoader pluginLoader, IDbSlashCommand? dbSlashCommand)
|
internal static async Task<Result> TryStartSlashCommand(this IDbSlashCommand? dbSlashCommand)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (dbSlashCommand is null)
|
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();
|
var builder = new SlashCommandBuilder();
|
||||||
@@ -60,28 +60,27 @@ internal static class PluginLoaderExtensions
|
|||||||
|
|
||||||
foreach(ulong guildId in Application.CurrentApplication.ServerIDs)
|
foreach(ulong guildId in Application.CurrentApplication.ServerIDs)
|
||||||
{
|
{
|
||||||
bool result = await pluginLoader.EnableSlashCommandPerGuild(guildId, builder);
|
bool result = await EnableSlashCommandPerGuild(guildId, builder);
|
||||||
|
|
||||||
if (!result)
|
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)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Application.Logger.Log($"Error starting slash command {dbSlashCommand.Name}: {e.Message}", typeof(PluginLoader), LogType.Error);
|
return Result.Failure("Error starting slash command");
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<bool> EnableSlashCommandPerGuild(this PluginLoader pluginLoader, ulong guildId, SlashCommandBuilder builder)
|
private static async Task<bool> EnableSlashCommandPerGuild(ulong guildId, SlashCommandBuilder builder)
|
||||||
{
|
{
|
||||||
SocketGuild? guild = pluginLoader._Client.GetGuild(guildId);
|
SocketGuild? guild = Application.CurrentApplication.DiscordBotClient.Client.GetGuild(guildId);
|
||||||
if (guild is null)
|
if (guild is null)
|
||||||
{
|
{
|
||||||
Application.Logger.Log("Failed to get guild with ID " + guildId, typeof(PluginLoader), LogType.Error);
|
Application.Logger.Log("Failed to get guild with ID " + guildId, typeof(PluginLoader), LogType.Error);
|
||||||
|
|||||||
42
DiscordBotCore/Loaders/PluginLoaderResult.cs
Normal file
42
DiscordBotCore/Loaders/PluginLoaderResult.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using DiscordBotCore.Interfaces;
|
||||||
|
using DiscordBotCore.Others;
|
||||||
|
using DiscordBotCore.Others.Exceptions;
|
||||||
|
|
||||||
|
namespace DiscordBotCore.Loaders;
|
||||||
|
|
||||||
|
|
||||||
|
public class PluginLoaderResult
|
||||||
|
{
|
||||||
|
private Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception> _Result;
|
||||||
|
|
||||||
|
public static PluginLoaderResult FromIDbCommand(IDbCommand command) => new PluginLoaderResult(new Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception>(command));
|
||||||
|
|
||||||
|
public static PluginLoaderResult FromIDbEvent(IDbEvent dbEvent) => new PluginLoaderResult(new Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception>(dbEvent));
|
||||||
|
|
||||||
|
public static PluginLoaderResult FromIDbSlashCommand(IDbSlashCommand slashCommand) => new PluginLoaderResult(new Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception>(slashCommand));
|
||||||
|
|
||||||
|
public static PluginLoaderResult FromICommandAction(ICommandAction commandAction) => new PluginLoaderResult(new Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception>(commandAction));
|
||||||
|
|
||||||
|
public static PluginLoaderResult FromException(Exception exception) => new PluginLoaderResult(new Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception>(exception));
|
||||||
|
public static PluginLoaderResult FromException(string exception) => new PluginLoaderResult(new Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception>(new Exception(message: exception)));
|
||||||
|
|
||||||
|
private PluginLoaderResult(Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception> result)
|
||||||
|
{
|
||||||
|
_Result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Match(Action<IDbCommand> commandAction, Action<IDbEvent> eventAction, Action<IDbSlashCommand> slashCommandAction,
|
||||||
|
Action<ICommandAction> commandActionAction, Action<Exception> exceptionAction)
|
||||||
|
{
|
||||||
|
_Result.Match(commandAction, eventAction, slashCommandAction, commandActionAction, exceptionAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TResult Match<TResult>(Func<IDbCommand, TResult> commandFunc, Func<IDbEvent, TResult> eventFunc,
|
||||||
|
Func<IDbSlashCommand, TResult> slashCommandFunc, Func<ICommandAction, TResult> commandActionFunc,
|
||||||
|
Func<Exception, TResult> exceptionFunc)
|
||||||
|
{
|
||||||
|
return _Result.Match(commandFunc, eventFunc, slashCommandFunc, commandActionFunc, exceptionFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -135,9 +135,9 @@ namespace DiscordBotCore.Modules
|
|||||||
var availableModules = await GetAllModules(module);
|
var availableModules = await GetAllModules(module);
|
||||||
|
|
||||||
Console.WriteLine("Please select a module of type " + 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("Author: " + availableModules[i].ModuleAuthor);
|
||||||
Console.WriteLine("Description: " + availableModules[i].ModuleDescription);
|
Console.WriteLine("Description: " + availableModules[i].ModuleDescription);
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ public class DbCommandExecutingArguments
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CleanContent = message.Content.Substring(Application.CurrentApplication.DiscordBotClient.BotPrefix.Length);
|
string? prefix = Application.CurrentApplication.ApplicationEnvironmentVariables.Get<string>("prefix");
|
||||||
|
CleanContent = message.Content.Substring(prefix?.Length ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
var split = CleanContent.Split(' ');
|
var split = CleanContent.Split(' ');
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace DiscordBotCore.Others.Exceptions
|
namespace DiscordBotCore.Others.Exceptions
|
||||||
{
|
{
|
||||||
internal class PluginNotFoundException : Exception
|
public class PluginNotFoundException : Exception
|
||||||
{
|
{
|
||||||
public PluginNotFoundException(string pluginName) : base($"Plugin {pluginName} was not found") { }
|
public PluginNotFoundException(string pluginName) : base($"Plugin {pluginName} was not found") { }
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace DiscordBotCore.Others
|
namespace DiscordBotCore.Others
|
||||||
{
|
{
|
||||||
|
|||||||
179
DiscordBotCore/Others/Option.cs
Normal file
179
DiscordBotCore/Others/Option.cs
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DiscordBotCore.Others;
|
||||||
|
|
||||||
|
|
||||||
|
public class Option2<T0, T1, TError> 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, T1, TError>(T0 item0) => new Option2<T0, T1, TError>(item0);
|
||||||
|
public static implicit operator Option2<T0, T1, TError>(T1 item1) => new Option2<T0, T1, TError>(item1);
|
||||||
|
public static implicit operator Option2<T0, T1, TError>(TError error) => new Option2<T0, T1, TError>(error);
|
||||||
|
|
||||||
|
public void Match(Action<T0> item0, Action<T1> item1, Action<TError> 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<TResult>(Func<T0, TResult> item0, Func<T1, TResult> item1, Func<TError, TResult> 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<T0, T1, T2, T3, TError> 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, T1, T2, T3, TError>(T0 item0) => new Option4<T0, T1, T2, T3, TError>(item0);
|
||||||
|
public static implicit operator Option4<T0, T1, T2, T3, TError>(T1 item1) => new Option4<T0, T1, T2, T3, TError>(item1);
|
||||||
|
public static implicit operator Option4<T0, T1, T2, T3, TError>(T2 item2) => new Option4<T0, T1, T2, T3, TError>(item2);
|
||||||
|
public static implicit operator Option4<T0, T1, T2, T3, TError>(T3 item3) => new Option4<T0, T1, T2, T3, TError>(item3);
|
||||||
|
public static implicit operator Option4<T0, T1, T2, T3, TError>(TError error) => new Option4<T0, T1, T2, T3, TError>(error);
|
||||||
|
|
||||||
|
|
||||||
|
public void Match(Action<T0> item0, Action<T1> item1, Action<T2> item2, Action<T3> item3, Action<TError> 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<TResult>(Func<T0, TResult> item0, Func<T1, TResult> item1, Func<T2, TResult> item2, Func<T3, TResult> item3, Func<TError, TResult> 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"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
64
DiscordBotCore/Others/Result.cs
Normal file
64
DiscordBotCore/Others/Result.cs
Normal file
@@ -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<Exception> exceptionAction)
|
||||||
|
{
|
||||||
|
if (_Result.HasValue && _Result.Value)
|
||||||
|
{
|
||||||
|
successAction();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
exceptionAction(Exception!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Result<T>
|
||||||
|
{
|
||||||
|
private readonly OneOf<T, Exception> _Result;
|
||||||
|
|
||||||
|
private Result(OneOf<T, Exception> result)
|
||||||
|
{
|
||||||
|
_Result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result<T> From (T value) => new Result<T>(new OneOf<T, Exception>(value));
|
||||||
|
public static implicit operator Result<T>(Exception exception) => new Result<T>(new OneOf<T, Exception>(exception));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void Match(Action<T> valueAction, Action<Exception> exceptionAction)
|
||||||
|
{
|
||||||
|
_Result.Match(valueAction, exceptionAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TResult Match<TResult>(Func<T, TResult> valueFunc, Func<Exception, TResult> exceptionFunc)
|
||||||
|
{
|
||||||
|
return _Result.Match(valueFunc, exceptionFunc);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,8 +49,21 @@ public class CustomSettingsDictionary : CustomSettingsDictionaryBase<string, obj
|
|||||||
|
|
||||||
public override async Task LoadFromFile()
|
public override async Task LoadFromFile()
|
||||||
{
|
{
|
||||||
|
if (!File.Exists(_DiskLocation))
|
||||||
|
{
|
||||||
|
await SaveToFile();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
string jsonContent = await File.ReadAllTextAsync(_DiskLocation);
|
string jsonContent = await File.ReadAllTextAsync(_DiskLocation);
|
||||||
var jObject = JsonConvert.DeserializeObject<JObject>(jsonContent);
|
var jObject = JsonConvert.DeserializeObject<JObject>(jsonContent);
|
||||||
|
|
||||||
|
if (jObject is null)
|
||||||
|
{
|
||||||
|
await SaveToFile();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_InternalDictionary.Clear();
|
_InternalDictionary.Clear();
|
||||||
|
|
||||||
foreach (var kvp in jObject)
|
foreach (var kvp in jObject)
|
||||||
|
|||||||
Reference in New Issue
Block a user