From 9c98d2e2192e80f1898ed1e1c32dfc6376438643 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Sat, 10 Aug 2024 20:27:59 +0300 Subject: [PATCH] Updated Module engine --- DiscordBot/Bot/Actions/Clear.cs | 2 +- DiscordBot/Bot/Actions/Extra/PluginMethods.cs | 4 - DiscordBot/Bot/Actions/Help.cs | 1 - DiscordBot/Bot/Actions/Module.cs | 7 +- DiscordBot/Entry.cs | 6 - DiscordBotCore/Application.cs | 117 ++++++---- DiscordBotCore/Interfaces/Modules/IModule.cs | 5 +- DiscordBotCore/Modules/ModuleData.cs | 4 +- DiscordBotCore/Modules/ModuleDownloader.cs | 31 --- DiscordBotCore/Modules/ModuleManager.cs | 209 ++++++++++++++++-- DiscordBotCore/Modules/ModuleOnlineData.cs | 21 ++ .../Others/Exceptions/ModuleMethodNotFound.cs | 13 ++ .../Others/Exceptions/ModuleNotFound.cs | 15 ++ .../Others/Exceptions/RequireInstallModule.cs | 23 ++ .../Plugin/OnlineScriptDependencyInfo.cs | 8 +- Modules/LoggerModule/Entry.cs | 13 +- 16 files changed, 355 insertions(+), 124 deletions(-) delete mode 100644 DiscordBotCore/Modules/ModuleDownloader.cs create mode 100644 DiscordBotCore/Modules/ModuleOnlineData.cs create mode 100644 DiscordBotCore/Others/Exceptions/ModuleMethodNotFound.cs create mode 100644 DiscordBotCore/Others/Exceptions/ModuleNotFound.cs create mode 100644 DiscordBotCore/Others/Exceptions/RequireInstallModule.cs diff --git a/DiscordBot/Bot/Actions/Clear.cs b/DiscordBot/Bot/Actions/Clear.cs index dfc8188..f24bc4a 100644 --- a/DiscordBot/Bot/Actions/Clear.cs +++ b/DiscordBot/Bot/Actions/Clear.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using System.Linq; + using System.Threading.Tasks; using DiscordBotCore.Interfaces; using DiscordBotCore.Others; diff --git a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs index 936f387..c66609e 100644 --- a/DiscordBot/Bot/Actions/Extra/PluginMethods.cs +++ b/DiscordBot/Bot/Actions/Extra/PluginMethods.cs @@ -1,13 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.CompilerServices; using System.Threading.Tasks; using DiscordBot.Utilities; using DiscordBotCore; -using DiscordBotCore.Interfaces.PluginManager; using DiscordBotCore.Loaders; using DiscordBotCore.Online; using DiscordBotCore.Others; @@ -22,8 +20,6 @@ internal static class PluginMethods internal static async Task List() { - - Console.WriteLine($"Fetching plugin list from branch {Application.CurrentApplication.PluginManager.Branch} ..."); var data = await ConsoleUtilities.ExecuteWithProgressBar(Application.CurrentApplication.PluginManager.GetPluginsList(), "Reading remote database"); diff --git a/DiscordBot/Bot/Actions/Help.cs b/DiscordBot/Bot/Actions/Help.cs index 07c92e3..8d25716 100644 --- a/DiscordBot/Bot/Actions/Help.cs +++ b/DiscordBot/Bot/Actions/Help.cs @@ -9,7 +9,6 @@ using DiscordBotCore.Interfaces; using DiscordBotCore.Others; using DiscordBotCore.Others.Actions; using Spectre.Console; -using Spectre.Console.Rendering; namespace DiscordBot.Bot.Actions; diff --git a/DiscordBot/Bot/Actions/Module.cs b/DiscordBot/Bot/Actions/Module.cs index ec2d688..f054c0c 100644 --- a/DiscordBot/Bot/Actions/Module.cs +++ b/DiscordBot/Bot/Actions/Module.cs @@ -1,10 +1,7 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; using DiscordBotCore; using DiscordBotCore.Interfaces; -using DiscordBotCore.Interfaces.Modules; -using DiscordBotCore.Modules; using DiscordBotCore.Others; using DiscordBotCore.Others.Actions; @@ -44,7 +41,7 @@ namespace DiscordBot.Bot.Actions private void ListLoadedModules() { - var modules = DiscordBotCore.Application.CurrentApplication.GetLoadedCoreModules(); + var modules = Application.CurrentApplication.GetLoadedCoreModules(); foreach (var module in modules) { Application.Logger.Log("Module: " + module.Key.ModuleName, this, LogType.Info); diff --git a/DiscordBot/Entry.cs b/DiscordBot/Entry.cs index 8c139f4..e0cdbaa 100644 --- a/DiscordBot/Entry.cs +++ b/DiscordBot/Entry.cs @@ -39,12 +39,6 @@ public static class Entry } Directory.Delete("temp"); - }), - - new StartupAction("--module-install", (args) => { - ModuleDownloader moduleDownloader = new ModuleDownloader(args[0]); - - ConsoleUtilities.ExecuteTaskWithBuiltInProgress(moduleDownloader.DownloadModule, "Downloading logger module").Wait(); }) ]; diff --git a/DiscordBotCore/Application.cs b/DiscordBotCore/Application.cs index 897a3d7..e746e00 100644 --- a/DiscordBotCore/Application.cs +++ b/DiscordBotCore/Application.cs @@ -1,20 +1,23 @@ -using DiscordBotCore.Interfaces.PluginManager; -using DiscordBotCore.Online; -using DiscordBotCore.Others; -using DiscordBotCore.Others.Actions; -using DiscordBotCore.Plugin; - using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.IO; using System.Threading.Tasks; -using DiscordBotCore.Others.Exceptions; -using DiscordBotCore.Modules; -using DiscordBotCore.Interfaces.Modules; + +using DiscordBotCore.Online; using DiscordBotCore.Online.Helpers; + +using DiscordBotCore.Others; +using DiscordBotCore.Others.Actions; +using DiscordBotCore.Others.Exceptions; using DiscordBotCore.Others.Settings; +using DiscordBotCore.Modules; +using DiscordBotCore.Plugin; + +using DiscordBotCore.Interfaces.PluginManager; +using DiscordBotCore.Interfaces.Modules; namespace DiscordBotCore { @@ -23,6 +26,9 @@ namespace DiscordBotCore /// public sealed class Application { + /// + /// Defines the current application. This is a singleton class + /// public static Application CurrentApplication { get; private set; } = null!; private static readonly string _ConfigFile = "./Data/Resources/config.json"; @@ -34,13 +40,13 @@ namespace DiscordBotCore public List ServerIDs => ApplicationEnvironmentVariables.GetList("ServerID", new List()); public string PluginDatabase => ApplicationEnvironmentVariables.Get("PluginDatabase", _PluginsDatabaseFile); - - private ModuleManager _ModuleManager; - - public CustomSettingsDictionary ApplicationEnvironmentVariables { get; private set; } - public InternalActionManager InternalActionManager { get; private set; } - public IPluginManager PluginManager { get; private set; } - public Bot.App DiscordBotClient { get; internal set; } + + 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() { @@ -50,12 +56,12 @@ namespace DiscordBotCore Console.WriteLine("No internet connection detected. Exiting ..."); Environment.Exit(0); } - + if (CurrentApplication is not null) return; CurrentApplication = new Application(); - + Directory.CreateDirectory(_ResourcesFolder); Directory.CreateDirectory(_PluginsFolder); Directory.CreateDirectory(_LogsFolder); @@ -65,18 +71,19 @@ namespace DiscordBotCore CurrentApplication.ApplicationEnvironmentVariables.Add("PluginFolder", _PluginsFolder); CurrentApplication.ApplicationEnvironmentVariables.Add("ResourceFolder", _ResourcesFolder); CurrentApplication.ApplicationEnvironmentVariables.Add("LogsFolder", _LogsFolder); - - + CurrentApplication._ModuleManager = new ModuleManager(); await CurrentApplication._ModuleManager.LoadModules(); - + var requirements = await CurrentApplication._ModuleManager.CheckRequiredModules(); + await CurrentApplication._ModuleManager.SolveRequirementIssues(requirements); + if (!File.Exists(_PluginsDatabaseFile)) { List plugins = new(); await JsonManager.SaveToJsonFile(_PluginsDatabaseFile, plugins); } - + #if DEBUG CurrentApplication.PluginManager = new PluginManager("tests"); #else @@ -88,51 +95,59 @@ namespace DiscordBotCore CurrentApplication.InternalActionManager = new InternalActionManager(); await CurrentApplication.InternalActionManager.Initialize(); - } + /// + /// A special class that is designed to log messages. It is a wrapper around the Logger module + /// The logger module is required to have this specific methods: + ///

+ /// BaseLogException(Exception ex, object sender, bool fullStackTrace)
+ /// BaseLog(string message)
+ /// LogWithTypeAndFormat(string message, LogType logType, string format)
+ /// LogWithType(string message, LogType logType)
+ /// LogWithSender(string message, object sender)
+ /// 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. + ///
public static class Logger { + private static readonly KeyValuePair _LoggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger); public static async void LogException(Exception ex, object sender, bool fullStackTrace = false) { - var loggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger); - await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["BaseLogException"], [ex, sender, fullStackTrace]); + await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["BaseLogException"], [ex, sender, fullStackTrace]); } public static async void Log(string message) { - var loggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger); - await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["BaseLog"], [message]); + await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["BaseLog"], [message]); } public static async void Log(string message, LogType logType, string format) { - var loggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger); - await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["LogWithTypeAndFormat"], [message, logType, format]); + await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["LogWithTypeAndFormat"], [message, logType, format]); } public static async void Log(string message, LogType logType) { - var loggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger); - await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["LogWithType"], [message, logType]); + await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["LogWithType"], [message, logType]); } public static async void Log(string message, object sender) { - var loggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger); - await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["LogWithSender"], [message, sender]); + await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["LogWithSender"], [message, sender]); } public static async void Log(string message, object sender, LogType type) { - var loggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger); - await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["LogWithTypeAndSender"], [message, sender, type]); + await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["LogWithTypeAndSender"], [message, sender, type]); } - + public static async void SetOutFunction(Action outFunction) { - var loggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger); - await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["SetPrintFunction"], [outFunction]); + await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["SetPrintFunction"], [outFunction]); } } @@ -157,15 +172,33 @@ namespace DiscordBotCore public static async Task GetPluginDependencyPath(string dependencyName, string? pluginName = null) { string? dependencyLocation; - if(pluginName is null) + if (pluginName is null) dependencyLocation = await Application.CurrentApplication.PluginManager.GetDependencyLocation(dependencyName); else dependencyLocation = await Application.CurrentApplication.PluginManager.GetDependencyLocation(dependencyName, pluginName); - - if(dependencyLocation is null) + + if (dependencyLocation is null) throw new DependencyNotFoundException($"Dependency {dependencyName} not found", pluginName); - + return dependencyLocation; } + + /// + /// Invokes a method from a module + /// + public static async Task InvokeModuleMethod(string moduleName, string methodName, object[] parameters) + { + KeyValuePair module = CurrentApplication._ModuleManager.GetModule(moduleName); + await CurrentApplication._ModuleManager.InvokeMethod(module.Value, module.Value.MethodMapping[methodName], parameters); + } + + /// + /// Invokes a method from a module and returns the result + /// + public static async Task InvokeModuleMethodWithResponse(string moduleName, string methodName, object[] parameters) + { + KeyValuePair module = CurrentApplication._ModuleManager.GetModule(moduleName); + return await CurrentApplication._ModuleManager.InvokeMethodWithReturnValue(module.Value, module.Value.MethodMapping[methodName], parameters); + } } } diff --git a/DiscordBotCore/Interfaces/Modules/IModule.cs b/DiscordBotCore/Interfaces/Modules/IModule.cs index 60e9c9e..4471e2e 100644 --- a/DiscordBotCore/Interfaces/Modules/IModule.cs +++ b/DiscordBotCore/Interfaces/Modules/IModule.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; namespace DiscordBotCore.Interfaces.Modules { @@ -16,6 +17,8 @@ namespace DiscordBotCore.Interfaces.Modules { public ModuleType ModuleType { get; } public string Name { get; } + public IDictionary MethodMapping { get; } + public Task Initialize(); } } diff --git a/DiscordBotCore/Modules/ModuleData.cs b/DiscordBotCore/Modules/ModuleData.cs index 155ca1a..63c4ecc 100644 --- a/DiscordBotCore/Modules/ModuleData.cs +++ b/DiscordBotCore/Modules/ModuleData.cs @@ -7,13 +7,11 @@ public class ModuleData public string ModuleName { get; set; } public string ModulePath { get; set; } public bool IsEnabled { get; set; } = true; - public IDictionary MethodMapping { get; set; } - public ModuleData(string moduleName, string modulePath, IDictionary methodMapping, bool isEnabled) + public ModuleData(string moduleName, string modulePath, bool isEnabled) { ModuleName = moduleName; ModulePath = modulePath; - MethodMapping = methodMapping; IsEnabled = isEnabled; } } diff --git a/DiscordBotCore/Modules/ModuleDownloader.cs b/DiscordBotCore/Modules/ModuleDownloader.cs deleted file mode 100644 index 443481c..0000000 --- a/DiscordBotCore/Modules/ModuleDownloader.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; - -using DiscordBotCore.Online; - -namespace DiscordBotCore.Modules -{ - public class ModuleDownloader - { - private readonly string _ModuleName; - private const string _BaseUrl = "https://raw.githubusercontent.com/andreitdr/SethPlugins/tests/Modules/"; - - public ModuleDownloader(string moduleName) - { - _ModuleName = moduleName; - } - - public async Task DownloadModule(IProgress progressToWrite) - { - string? moduleFolder = Application.CurrentApplication.ApplicationEnvironmentVariables.Get("ModuleFolder"); - - if(moduleFolder is null) - throw new DirectoryNotFoundException("Module folder not found"); // Should never happen - - Directory.CreateDirectory(moduleFolder); - string url = _BaseUrl + _ModuleName + ".dll"; - await ServerCom.DownloadFileAsync(url, moduleFolder + "/" + _ModuleName + ".dll", progressToWrite); - } - } -} diff --git a/DiscordBotCore/Modules/ModuleManager.cs b/DiscordBotCore/Modules/ModuleManager.cs index 73e5eaf..2155877 100644 --- a/DiscordBotCore/Modules/ModuleManager.cs +++ b/DiscordBotCore/Modules/ModuleManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -6,6 +6,9 @@ using System.Threading.Tasks; using DiscordBotCore.Interfaces.Modules; using DiscordBotCore.Loaders; +using DiscordBotCore.Online; +using DiscordBotCore.Others; +using DiscordBotCore.Others.Exceptions; using Newtonsoft.Json; namespace DiscordBotCore.Modules @@ -14,22 +17,149 @@ namespace DiscordBotCore.Modules { private static readonly string _BaseModuleFolder = "./Data/Modules"; private static readonly string _BaseModuleConfig = "./Data/Resources/modules.json"; - internal Dictionary Modules { get; set; } + private const string _ModuleDatabase = "https://raw.githubusercontent.com/andreitdr/SethPlugins/tests/modules.json"; + + internal Dictionary Modules { get; set; } + public ModuleManager() { Application.CurrentApplication.ApplicationEnvironmentVariables.Get("ModuleFolder", _BaseModuleFolder); Modules = new Dictionary(); } - public KeyValuePair GetModule(string moduleName) + public async Task> GetAllModules(ModuleType? moduleTypeFilter = null) { - return Modules.FirstOrDefault(module => module.Key.ModuleName == moduleName); + string jsonDatabaseRemote = await ServerCom.GetAllTextFromUrl(_ModuleDatabase); + + var modules = await JsonManager.ConvertFromJson>(jsonDatabaseRemote); + + if(moduleTypeFilter is not null) + modules = modules.FindAll(m => m.ModuleType == moduleTypeFilter); + + return modules; } + public async Task InstallModule(string moduleName, IProgress progressToWrite) + { + string? moduleFolder = Application.CurrentApplication.ApplicationEnvironmentVariables.Get("ModuleFolder"); + + if(moduleFolder is null) + throw new DirectoryNotFoundException("Module folder not found"); // Should never happen + + Directory.CreateDirectory(moduleFolder); + + List modules = await GetAllModules(); + + string url = modules.Find(m => m.ModuleName == moduleName)?.ModuleDownloadUrl ?? string.Empty; + + if(string.IsNullOrEmpty(url)) + return; + + string filePath = moduleFolder + "/" + moduleName + ".dll"; + await ServerCom.DownloadFileAsync(url, filePath, progressToWrite); + + ModuleData localModuleData = new ModuleData(moduleName, filePath, true); + + await AddModuleToDatabase(localModuleData); + } + + public KeyValuePair GetModule(string moduleName) + { + var result = Modules.FirstOrDefault(module => module.Key.ModuleName == moduleName); + + if (result.Value is null || result.Key is null) + { + throw new ModuleNotFound(moduleName); + } + + return result; + } + public KeyValuePair GetModule(ModuleType moduleType) { - return Modules.First(module => module.Value.ModuleType == moduleType); + var result = Modules.FirstOrDefault(module => module.Value.ModuleType == moduleType); + + if (result.Value is null || result.Key is null) + { + throw new ModuleNotFound(moduleType); + } + + return result; + } + + public async Task AddModuleToDatabase(ModuleData moduleData) + { + string moduleConfigPath = Application.CurrentApplication.ApplicationEnvironmentVariables + .Get("ModuleConfig", _BaseModuleConfig); + + List? listOfModuleData = null; + if (File.Exists(moduleConfigPath)) + { + string moduleConfigFile = await File.ReadAllTextAsync(moduleConfigPath); + listOfModuleData = JsonConvert.DeserializeObject>(moduleConfigFile); + } + + + if (listOfModuleData is null) + { + listOfModuleData = new List(); + } + + listOfModuleData.Add(moduleData); + + string json = JsonConvert.SerializeObject(listOfModuleData, Formatting.Indented); + await File.WriteAllTextAsync(moduleConfigPath, json); + } + + public Task CheckRequiredModules() + { + RequireInstallModule requireInstallModule = new RequireInstallModule(); + if (!Modules.Any(module => module.Value.ModuleType == ModuleType.Logger)) + { + requireInstallModule.AddType(ModuleType.Logger); + } + + return Task.FromResult(requireInstallModule); + } + + public async Task SolveRequirementIssues(RequireInstallModule requirements) + { + if (!requirements.RequireAny) + { + return; + } + + foreach (var module in requirements.RequiredModules) + { + var availableModules = await GetAllModules(module); + + Console.WriteLine("Please select a module of type " + module); + for (int i = 0; i < availableModules.Count; i++) + { + Console.WriteLine(i + " - " + availableModules[i].ModuleName); + Console.WriteLine("Author: " + availableModules[i].ModuleAuthor); + Console.WriteLine("Description: " + availableModules[i].ModuleDescription); + + Console.WriteLine(); + } + + Console.WriteLine("Please select a module by typing the number:"); + int selectedModule = int.Parse(Console.ReadLine() ?? string.Empty); + + if (selectedModule < 1 || selectedModule > availableModules.Count) + { + Console.WriteLine("Invalid module selected"); + Environment.Exit(-1); + } + + IProgress progress = new Progress(f => Console.Write($"\b{f}")); + await InstallModule(availableModules[selectedModule - 1].ModuleName, progress); + } + + + Console.WriteLine("All required modules installed. Please restart the application"); + System.Diagnostics.Process.Start(System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName); } public async Task LoadModules() @@ -37,47 +167,84 @@ namespace DiscordBotCore.Modules string moduleConfigPath = Application.CurrentApplication.ApplicationEnvironmentVariables .Get("ModuleConfig", _BaseModuleConfig); - string moduleConfigFile = await File.ReadAllTextAsync(moduleConfigPath); - List? listOfModuleData = JsonConvert.DeserializeObject>(moduleConfigFile); - - if(listOfModuleData is null) + if(!File.Exists(moduleConfigPath)) return; - + + string moduleConfigFile = await File.ReadAllTextAsync(moduleConfigPath); + List? listOfModuleData = JsonConvert.DeserializeObject>(moduleConfigFile); + + if (listOfModuleData is null) + return; + if (!listOfModuleData.Any()) { return; } - + ModuleLoader moduleLoader = new ModuleLoader(listOfModuleData); await moduleLoader.LoadFileModules(); var modules = await moduleLoader.LoadModules(); - + foreach (var module in modules) { - + ModuleData? moduleData = listOfModuleData.FirstOrDefault(data => data.ModuleName == module.Name); if (moduleData is null) { continue; } - + if (moduleData.IsEnabled) { - await module.Initialize(); // TODO: Add error handling - Modules.Add(moduleData, module); + try{ + await module.Initialize(); + Modules.Add(moduleData, module); + }catch(Exception e){ + Console.WriteLine($"Error loading module {moduleData.ModuleName}: {e.Message}"); + } } } } + public async Task InvokeMethodWithReturnValue(string moduleName, string methodName, object[] parameters) + { + IModule module = GetModule(moduleName).Value; + var method = module.GetType().GetMethod(methodName); + + if (method is null) + { + throw new ModuleMethodNotFound(module, methodName); + } + + object? result = await Task.Run(() => method.Invoke(module, parameters)); + + return result; + } + + public async Task InvokeMethodWithReturnValue(IModule module, string methodName, object[] parameters) + { + var method = module.GetType().GetMethod(methodName); + + if (method is null) + { + throw new ModuleMethodNotFound(module, methodName); + } + + object? result = await Task.Run(() => method.Invoke(module, parameters)); + + return result; + } + + public async Task InvokeMethod(string moduleName, string methodName, object[] parameters) { IModule module = GetModule(moduleName).Value; var method = module.GetType().GetMethod(methodName); - + if (method is null) { - throw new Exception("Method not found"); // TODO: Add custom exception + throw new ModuleMethodNotFound(module, methodName); } await Task.Run(() => method.Invoke(module, parameters)); @@ -86,15 +253,13 @@ namespace DiscordBotCore.Modules public async Task InvokeMethod(IModule module, string methodName, object[] parameters) { var method = module.GetType().GetMethod(methodName); - + if (method is null) { - throw new Exception($"Method not found {methodName}"); + throw new ModuleMethodNotFound(module, methodName); } await Task.Run(() => method.Invoke(module, parameters)); } - - } } diff --git a/DiscordBotCore/Modules/ModuleOnlineData.cs b/DiscordBotCore/Modules/ModuleOnlineData.cs new file mode 100644 index 0000000..af52d77 --- /dev/null +++ b/DiscordBotCore/Modules/ModuleOnlineData.cs @@ -0,0 +1,21 @@ +using DiscordBotCore.Interfaces.Modules; + +namespace DiscordBotCore.Modules; + +public class ModuleOnlineData +{ + public string ModuleName { get; set; } + public string ModuleDownloadUrl { get; set; } + public string ModuleDescription { get; set; } + public string ModuleAuthor { get; set; } + public ModuleType ModuleType { get; set; } + + public ModuleOnlineData(string moduleName, string moduleDownloadUrl, ModuleType moduleType, string moduleDescription, string moduleAuthor) + { + ModuleName = moduleName; + ModuleDownloadUrl = moduleDownloadUrl; + ModuleType = moduleType; + ModuleDescription = moduleDescription; + ModuleAuthor = moduleAuthor; + } +} diff --git a/DiscordBotCore/Others/Exceptions/ModuleMethodNotFound.cs b/DiscordBotCore/Others/Exceptions/ModuleMethodNotFound.cs new file mode 100644 index 0000000..f1ed2a4 --- /dev/null +++ b/DiscordBotCore/Others/Exceptions/ModuleMethodNotFound.cs @@ -0,0 +1,13 @@ +using System; +using DiscordBotCore.Interfaces.Modules; + +namespace DiscordBotCore.Others.Exceptions; + +public class ModuleMethodNotFound : Exception +{ + private IModule _SearchedModule; + public ModuleMethodNotFound(IModule module, string methodName) : base($"Method not found {methodName} in module {module.Name}") + { + _SearchedModule = module; + } +} diff --git a/DiscordBotCore/Others/Exceptions/ModuleNotFound.cs b/DiscordBotCore/Others/Exceptions/ModuleNotFound.cs new file mode 100644 index 0000000..14b066f --- /dev/null +++ b/DiscordBotCore/Others/Exceptions/ModuleNotFound.cs @@ -0,0 +1,15 @@ +using System; +using DiscordBotCore.Interfaces.Modules; + +namespace DiscordBotCore.Others.Exceptions; + +public class ModuleNotFound : Exception +{ + public ModuleNotFound(string moduleName) : base($"Module not found: {moduleName}") + { + } + + public ModuleNotFound(ModuleType moduleType) : base($"No module with type {moduleType} found") + { + } +} diff --git a/DiscordBotCore/Others/Exceptions/RequireInstallModule.cs b/DiscordBotCore/Others/Exceptions/RequireInstallModule.cs new file mode 100644 index 0000000..e559154 --- /dev/null +++ b/DiscordBotCore/Others/Exceptions/RequireInstallModule.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using DiscordBotCore.Interfaces.Modules; +using DiscordBotCore.Modules; + +namespace DiscordBotCore.Others.Exceptions; + +public class RequireInstallModule +{ + private List RequiredModulesWithType { get; } + + public RequireInstallModule() + { + RequiredModulesWithType = new List(); + } + + public void AddType (ModuleType moduleType) + { + RequiredModulesWithType.Add(moduleType); + } + + public bool RequireAny => RequiredModulesWithType.Count > 0; + public IList RequiredModules => RequiredModulesWithType; +} diff --git a/DiscordBotCore/Plugin/OnlineScriptDependencyInfo.cs b/DiscordBotCore/Plugin/OnlineScriptDependencyInfo.cs index 83e6f8d..5999876 100644 --- a/DiscordBotCore/Plugin/OnlineScriptDependencyInfo.cs +++ b/DiscordBotCore/Plugin/OnlineScriptDependencyInfo.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace DiscordBotCore.Plugin +namespace DiscordBotCore.Plugin { public class OnlineScriptDependencyInfo { diff --git a/Modules/LoggerModule/Entry.cs b/Modules/LoggerModule/Entry.cs index 5159342..a6ca491 100644 --- a/Modules/LoggerModule/Entry.cs +++ b/Modules/LoggerModule/Entry.cs @@ -7,7 +7,18 @@ namespace LoggerModule { public string Name => "LoggerModule"; public ModuleType ModuleType => ModuleType.Logger; - + + public IDictionary MethodMapping => new Dictionary + { + {"BaseLog", "LogMessage"}, + {"LogWithTypeAndFormat", "LogMessageWithTypeAndFormat"}, + {"LogWithType", "LogMessageWithType"}, + {"LogWithSender", "LogMessageWithSender"}, + {"LogWithTypeAndSender", "LogMessageWithTypeAndSender"}, + {"BaseLogException", "LogExceptionWithSenderAndFullStack"}, + {"SetPrintFunction", "SetOutFunction"}, + }; + const string _LogFolder = "./Data/Logs/"; const string _LogFormat = "{ThrowTime} {SenderName} {Message}";