Updated Module engine

This commit is contained in:
2024-08-10 20:27:59 +03:00
parent 18a059af0e
commit 9c98d2e219
16 changed files with 355 additions and 124 deletions

View File

@@ -1,6 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordBotCore.Interfaces; using DiscordBotCore.Interfaces;
using DiscordBotCore.Others; using DiscordBotCore.Others;

View File

@@ -1,13 +1,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordBot.Utilities; using DiscordBot.Utilities;
using DiscordBotCore; using DiscordBotCore;
using DiscordBotCore.Interfaces.PluginManager;
using DiscordBotCore.Loaders; using DiscordBotCore.Loaders;
using DiscordBotCore.Online; using DiscordBotCore.Online;
using DiscordBotCore.Others; using DiscordBotCore.Others;
@@ -22,8 +20,6 @@ internal static class PluginMethods
internal static async Task List() internal static async Task List()
{ {
Console.WriteLine($"Fetching plugin list from branch {Application.CurrentApplication.PluginManager.Branch} ..."); Console.WriteLine($"Fetching plugin list from branch {Application.CurrentApplication.PluginManager.Branch} ...");
var data = await ConsoleUtilities.ExecuteWithProgressBar(Application.CurrentApplication.PluginManager.GetPluginsList(), "Reading remote database"); var data = await ConsoleUtilities.ExecuteWithProgressBar(Application.CurrentApplication.PluginManager.GetPluginsList(), "Reading remote database");

View File

@@ -9,7 +9,6 @@ using DiscordBotCore.Interfaces;
using DiscordBotCore.Others; using DiscordBotCore.Others;
using DiscordBotCore.Others.Actions; using DiscordBotCore.Others.Actions;
using Spectre.Console; using Spectre.Console;
using Spectre.Console.Rendering;
namespace DiscordBot.Bot.Actions; namespace DiscordBot.Bot.Actions;

View File

@@ -1,10 +1,7 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordBotCore; using DiscordBotCore;
using DiscordBotCore.Interfaces; using DiscordBotCore.Interfaces;
using DiscordBotCore.Interfaces.Modules;
using DiscordBotCore.Modules;
using DiscordBotCore.Others; using DiscordBotCore.Others;
using DiscordBotCore.Others.Actions; using DiscordBotCore.Others.Actions;
@@ -44,7 +41,7 @@ namespace DiscordBot.Bot.Actions
private void ListLoadedModules() private void ListLoadedModules()
{ {
var modules = DiscordBotCore.Application.CurrentApplication.GetLoadedCoreModules(); var modules = Application.CurrentApplication.GetLoadedCoreModules();
foreach (var module in modules) foreach (var module in modules)
{ {
Application.Logger.Log("Module: " + module.Key.ModuleName, this, LogType.Info); Application.Logger.Log("Module: " + module.Key.ModuleName, this, LogType.Info);

View File

@@ -39,12 +39,6 @@ public static class Entry
} }
Directory.Delete("temp"); Directory.Delete("temp");
}),
new StartupAction("--module-install", (args) => {
ModuleDownloader moduleDownloader = new ModuleDownloader(args[0]);
ConsoleUtilities.ExecuteTaskWithBuiltInProgress(moduleDownloader.DownloadModule, "Downloading logger module").Wait();
}) })
]; ];

View File

@@ -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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordBotCore.Others.Exceptions;
using DiscordBotCore.Modules; using DiscordBotCore.Online;
using DiscordBotCore.Interfaces.Modules;
using DiscordBotCore.Online.Helpers; using DiscordBotCore.Online.Helpers;
using DiscordBotCore.Others;
using DiscordBotCore.Others.Actions;
using DiscordBotCore.Others.Exceptions;
using DiscordBotCore.Others.Settings; using DiscordBotCore.Others.Settings;
using DiscordBotCore.Modules;
using DiscordBotCore.Plugin;
using DiscordBotCore.Interfaces.PluginManager;
using DiscordBotCore.Interfaces.Modules;
namespace DiscordBotCore namespace DiscordBotCore
{ {
@@ -23,6 +26,9 @@ namespace DiscordBotCore
/// </summary> /// </summary>
public sealed class Application public sealed class Application
{ {
/// <summary>
/// Defines the current application. This is a singleton class
/// </summary>
public static Application CurrentApplication { get; private set; } = null!; public static Application CurrentApplication { get; private set; } = null!;
private static readonly string _ConfigFile = "./Data/Resources/config.json"; private static readonly string _ConfigFile = "./Data/Resources/config.json";
@@ -35,12 +41,12 @@ namespace DiscordBotCore
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; private ModuleManager _ModuleManager = null!;
public CustomSettingsDictionary ApplicationEnvironmentVariables { get; private set; } public CustomSettingsDictionary ApplicationEnvironmentVariables { get; private set; } = null!;
public InternalActionManager InternalActionManager { get; private set; } public InternalActionManager InternalActionManager { get; private set; } = null!;
public IPluginManager PluginManager { get; private set; } public IPluginManager PluginManager { get; private set; } = null!;
public Bot.App DiscordBotClient { get; internal set; } public Bot.App DiscordBotClient { get; internal set; } = null!;
public static async Task CreateApplication() public static async Task CreateApplication()
{ {
@@ -66,9 +72,10 @@ namespace DiscordBotCore
CurrentApplication.ApplicationEnvironmentVariables.Add("ResourceFolder", _ResourcesFolder); CurrentApplication.ApplicationEnvironmentVariables.Add("ResourceFolder", _ResourcesFolder);
CurrentApplication.ApplicationEnvironmentVariables.Add("LogsFolder", _LogsFolder); CurrentApplication.ApplicationEnvironmentVariables.Add("LogsFolder", _LogsFolder);
CurrentApplication._ModuleManager = new ModuleManager(); CurrentApplication._ModuleManager = new ModuleManager();
await CurrentApplication._ModuleManager.LoadModules(); await CurrentApplication._ModuleManager.LoadModules();
var requirements = await CurrentApplication._ModuleManager.CheckRequiredModules();
await CurrentApplication._ModuleManager.SolveRequirementIssues(requirements);
if (!File.Exists(_PluginsDatabaseFile)) if (!File.Exists(_PluginsDatabaseFile))
{ {
@@ -88,51 +95,59 @@ namespace DiscordBotCore
CurrentApplication.InternalActionManager = new InternalActionManager(); CurrentApplication.InternalActionManager = new InternalActionManager();
await CurrentApplication.InternalActionManager.Initialize(); await CurrentApplication.InternalActionManager.Initialize();
} }
/// <summary>
/// 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:
/// <br/><br/>
/// BaseLogException(Exception ex, object sender, bool fullStackTrace)<br/>
/// BaseLog(string message)<br/>
/// LogWithTypeAndFormat(string message, LogType logType, string format)<br/>
/// LogWithType(string message, LogType logType)<br/>
/// LogWithSender(string message, object sender)<br/>
/// LogWithTypeAndSender(string message, object sender, LogType type)<br/>
/// SetPrintFunction(Action[in string] outFunction)<br/><br/>
///
/// If your custom logger does not have the following methods mapped, the application might crash.
/// Please check <b>modules.json</b> file for the mapping or refer to the official repository for the logger module.
/// </summary>
public static class Logger public static class Logger
{ {
private static readonly KeyValuePair<ModuleData, IModule> _LoggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger);
public static async void LogException(Exception ex, object sender, bool fullStackTrace = false) 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.Value.MethodMapping["BaseLogException"], [ex, sender, fullStackTrace]);
await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["BaseLogException"], [ex, sender, fullStackTrace]);
} }
public static async void Log(string message) public static async void Log(string message)
{ {
var loggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger); await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["BaseLog"], [message]);
await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["BaseLog"], [message]);
} }
public static async void Log(string message, LogType logType, string format) 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.Value.MethodMapping["LogWithTypeAndFormat"], [message, logType, format]);
await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["LogWithTypeAndFormat"], [message, logType, format]);
} }
public static async void Log(string message, LogType logType) public static async void Log(string message, LogType logType)
{ {
var loggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger); await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["LogWithType"], [message, logType]);
await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["LogWithType"], [message, logType]);
} }
public static async void Log(string message, object sender) public static async void Log(string message, object sender)
{ {
var loggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger); await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["LogWithSender"], [message, sender]);
await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["LogWithSender"], [message, sender]);
} }
public static async void Log(string message, object sender, LogType type) 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.Value.MethodMapping["LogWithTypeAndSender"], [message, sender, type]);
await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["LogWithTypeAndSender"], [message, sender, type]);
} }
public static async void SetOutFunction(Action<string> outFunction) public static async void SetOutFunction(Action<string> outFunction)
{ {
var loggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger); await CurrentApplication._ModuleManager.InvokeMethod(_LoggerModule.Value, _LoggerModule.Value.MethodMapping["SetPrintFunction"], [outFunction]);
await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["SetPrintFunction"], [outFunction]);
} }
} }
@@ -157,15 +172,33 @@ namespace DiscordBotCore
public static async Task<string> GetPluginDependencyPath(string dependencyName, string? pluginName = null) public static async Task<string> GetPluginDependencyPath(string dependencyName, string? pluginName = null)
{ {
string? dependencyLocation; string? dependencyLocation;
if(pluginName is null) if (pluginName is null)
dependencyLocation = await Application.CurrentApplication.PluginManager.GetDependencyLocation(dependencyName); dependencyLocation = await Application.CurrentApplication.PluginManager.GetDependencyLocation(dependencyName);
else else
dependencyLocation = await Application.CurrentApplication.PluginManager.GetDependencyLocation(dependencyName, pluginName); dependencyLocation = await Application.CurrentApplication.PluginManager.GetDependencyLocation(dependencyName, pluginName);
if(dependencyLocation is null) if (dependencyLocation is null)
throw new DependencyNotFoundException($"Dependency {dependencyName} not found", pluginName); throw new DependencyNotFoundException($"Dependency {dependencyName} not found", pluginName);
return dependencyLocation; return dependencyLocation;
} }
/// <summary>
/// Invokes a method from a module
/// </summary>
public static async Task InvokeModuleMethod(string moduleName, string methodName, object[] parameters)
{
KeyValuePair<ModuleData, IModule> module = CurrentApplication._ModuleManager.GetModule(moduleName);
await CurrentApplication._ModuleManager.InvokeMethod(module.Value, module.Value.MethodMapping[methodName], parameters);
}
/// <summary>
/// Invokes a method from a module and returns the result
/// </summary>
public static async Task<object?> InvokeModuleMethodWithResponse(string moduleName, string methodName, object[] parameters)
{
KeyValuePair<ModuleData, IModule> module = CurrentApplication._ModuleManager.GetModule(moduleName);
return await CurrentApplication._ModuleManager.InvokeMethodWithReturnValue(module.Value, module.Value.MethodMapping[methodName], parameters);
}
} }
} }

View File

@@ -1,4 +1,5 @@
using System.Threading.Tasks; using System.Collections.Generic;
using System.Threading.Tasks;
namespace DiscordBotCore.Interfaces.Modules namespace DiscordBotCore.Interfaces.Modules
{ {
@@ -16,6 +17,8 @@ namespace DiscordBotCore.Interfaces.Modules
{ {
public ModuleType ModuleType { get; } public ModuleType ModuleType { get; }
public string Name { get; } public string Name { get; }
public IDictionary<string, string> MethodMapping { get; }
public Task Initialize(); public Task Initialize();
} }
} }

View File

@@ -7,13 +7,11 @@ public class ModuleData
public string ModuleName { get; set; } public string ModuleName { get; set; }
public string ModulePath { get; set; } public string ModulePath { get; set; }
public bool IsEnabled { get; set; } = true; public bool IsEnabled { get; set; } = true;
public IDictionary<string, string> MethodMapping { get; set; }
public ModuleData(string moduleName, string modulePath, IDictionary<string, string> methodMapping, bool isEnabled) public ModuleData(string moduleName, string modulePath, bool isEnabled)
{ {
ModuleName = moduleName; ModuleName = moduleName;
ModulePath = modulePath; ModulePath = modulePath;
MethodMapping = methodMapping;
IsEnabled = isEnabled; IsEnabled = isEnabled;
} }
} }

View File

@@ -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<float> progressToWrite)
{
string? moduleFolder = Application.CurrentApplication.ApplicationEnvironmentVariables.Get<string>("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);
}
}
}

View File

@@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -6,6 +6,9 @@ using System.Threading.Tasks;
using DiscordBotCore.Interfaces.Modules; using DiscordBotCore.Interfaces.Modules;
using DiscordBotCore.Loaders; using DiscordBotCore.Loaders;
using DiscordBotCore.Online;
using DiscordBotCore.Others;
using DiscordBotCore.Others.Exceptions;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace DiscordBotCore.Modules namespace DiscordBotCore.Modules
@@ -14,6 +17,9 @@ namespace DiscordBotCore.Modules
{ {
private static readonly string _BaseModuleFolder = "./Data/Modules"; private static readonly string _BaseModuleFolder = "./Data/Modules";
private static readonly string _BaseModuleConfig = "./Data/Resources/modules.json"; private static readonly string _BaseModuleConfig = "./Data/Resources/modules.json";
private const string _ModuleDatabase = "https://raw.githubusercontent.com/andreitdr/SethPlugins/tests/modules.json";
internal Dictionary<ModuleData, IModule> Modules { get; set; } internal Dictionary<ModuleData, IModule> Modules { get; set; }
public ModuleManager() public ModuleManager()
@@ -22,14 +28,138 @@ namespace DiscordBotCore.Modules
Modules = new Dictionary<ModuleData, IModule>(); Modules = new Dictionary<ModuleData, IModule>();
} }
public async Task<List<ModuleOnlineData>> GetAllModules(ModuleType? moduleTypeFilter = null)
{
string jsonDatabaseRemote = await ServerCom.GetAllTextFromUrl(_ModuleDatabase);
var modules = await JsonManager.ConvertFromJson<List<ModuleOnlineData>>(jsonDatabaseRemote);
if(moduleTypeFilter is not null)
modules = modules.FindAll(m => m.ModuleType == moduleTypeFilter);
return modules;
}
public async Task InstallModule(string moduleName, IProgress<float> progressToWrite)
{
string? moduleFolder = Application.CurrentApplication.ApplicationEnvironmentVariables.Get<string>("ModuleFolder");
if(moduleFolder is null)
throw new DirectoryNotFoundException("Module folder not found"); // Should never happen
Directory.CreateDirectory(moduleFolder);
List<ModuleOnlineData> 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<ModuleData, IModule> GetModule(string moduleName) public KeyValuePair<ModuleData, IModule> GetModule(string moduleName)
{ {
return Modules.FirstOrDefault(module => module.Key.ModuleName == 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<ModuleData, IModule> GetModule(ModuleType moduleType) public KeyValuePair<ModuleData, IModule> 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<string>("ModuleConfig", _BaseModuleConfig);
List<ModuleData>? listOfModuleData = null;
if (File.Exists(moduleConfigPath))
{
string moduleConfigFile = await File.ReadAllTextAsync(moduleConfigPath);
listOfModuleData = JsonConvert.DeserializeObject<List<ModuleData>>(moduleConfigFile);
}
if (listOfModuleData is null)
{
listOfModuleData = new List<ModuleData>();
}
listOfModuleData.Add(moduleData);
string json = JsonConvert.SerializeObject(listOfModuleData, Formatting.Indented);
await File.WriteAllTextAsync(moduleConfigPath, json);
}
public Task<RequireInstallModule> 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<float> progress = new Progress<float>(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() public async Task LoadModules()
@@ -37,10 +167,13 @@ namespace DiscordBotCore.Modules
string moduleConfigPath = Application.CurrentApplication.ApplicationEnvironmentVariables string moduleConfigPath = Application.CurrentApplication.ApplicationEnvironmentVariables
.Get<string>("ModuleConfig", _BaseModuleConfig); .Get<string>("ModuleConfig", _BaseModuleConfig);
string moduleConfigFile = await File.ReadAllTextAsync(moduleConfigPath); if(!File.Exists(moduleConfigPath))
return;
string moduleConfigFile = await File.ReadAllTextAsync(moduleConfigPath);
List<ModuleData>? listOfModuleData = JsonConvert.DeserializeObject<List<ModuleData>>(moduleConfigFile); List<ModuleData>? listOfModuleData = JsonConvert.DeserializeObject<List<ModuleData>>(moduleConfigFile);
if(listOfModuleData is null) if (listOfModuleData is null)
return; return;
if (!listOfModuleData.Any()) if (!listOfModuleData.Any())
@@ -64,12 +197,46 @@ namespace DiscordBotCore.Modules
if (moduleData.IsEnabled) if (moduleData.IsEnabled)
{ {
await module.Initialize(); // TODO: Add error handling try{
Modules.Add(moduleData, module); await module.Initialize();
Modules.Add(moduleData, module);
}catch(Exception e){
Console.WriteLine($"Error loading module {moduleData.ModuleName}: {e.Message}");
}
} }
} }
} }
public async Task<object?> 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<object?> 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) public async Task InvokeMethod(string moduleName, string methodName, object[] parameters)
{ {
IModule module = GetModule(moduleName).Value; IModule module = GetModule(moduleName).Value;
@@ -77,7 +244,7 @@ namespace DiscordBotCore.Modules
if (method is null) 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)); await Task.Run(() => method.Invoke(module, parameters));
@@ -89,12 +256,10 @@ namespace DiscordBotCore.Modules
if (method is null) if (method is null)
{ {
throw new Exception($"Method not found {methodName}"); throw new ModuleMethodNotFound(module, methodName);
} }
await Task.Run(() => method.Invoke(module, parameters)); await Task.Run(() => method.Invoke(module, parameters));
} }
} }
} }

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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")
{
}
}

View File

@@ -0,0 +1,23 @@
using System.Collections.Generic;
using DiscordBotCore.Interfaces.Modules;
using DiscordBotCore.Modules;
namespace DiscordBotCore.Others.Exceptions;
public class RequireInstallModule
{
private List<ModuleType> RequiredModulesWithType { get; }
public RequireInstallModule()
{
RequiredModulesWithType = new List<ModuleType>();
}
public void AddType (ModuleType moduleType)
{
RequiredModulesWithType.Add(moduleType);
}
public bool RequireAny => RequiredModulesWithType.Count > 0;
public IList<ModuleType> RequiredModules => RequiredModulesWithType;
}

View File

@@ -1,10 +1,4 @@
using System; namespace DiscordBotCore.Plugin
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DiscordBotCore.Plugin
{ {
public class OnlineScriptDependencyInfo public class OnlineScriptDependencyInfo
{ {

View File

@@ -8,6 +8,17 @@ namespace LoggerModule
public string Name => "LoggerModule"; public string Name => "LoggerModule";
public ModuleType ModuleType => ModuleType.Logger; public ModuleType ModuleType => ModuleType.Logger;
public IDictionary<string, string> MethodMapping => new Dictionary<string, string>
{
{"BaseLog", "LogMessage"},
{"LogWithTypeAndFormat", "LogMessageWithTypeAndFormat"},
{"LogWithType", "LogMessageWithType"},
{"LogWithSender", "LogMessageWithSender"},
{"LogWithTypeAndSender", "LogMessageWithTypeAndSender"},
{"BaseLogException", "LogExceptionWithSenderAndFullStack"},
{"SetPrintFunction", "SetOutFunction"},
};
const string _LogFolder = "./Data/Logs/"; const string _LogFolder = "./Data/Logs/";
const string _LogFormat = "{ThrowTime} {SenderName} {Message}"; const string _LogFormat = "{ThrowTime} {SenderName} {Message}";