More fixes to the new config. Module loader reworked

This commit is contained in:
2024-08-06 22:47:59 +03:00
parent 27e25a9166
commit 18a059af0e
51 changed files with 390 additions and 301 deletions

View File

@@ -49,7 +49,7 @@ namespace DiscordBot.Bot.Actions
} }
PluginInfo pluginInfo = new PluginInfo(args[^1], new(1, 0, 0), [], false, true, args.Contains("-enabled")); PluginInfo pluginInfo = new PluginInfo(args[^1], new(1, 0, 0), [], false, true, args.Contains("-enabled"));
Application.CurrentApplication.Logger.Log("Adding plugin: " + args[^1]); Application.Logger.Log("Adding plugin: " + args[^1]);
await Application.CurrentApplication.PluginManager.AppendPluginToDatabase(pluginInfo); await Application.CurrentApplication.PluginManager.AppendPluginToDatabase(pluginInfo);
} }
} }

View File

@@ -26,7 +26,7 @@ public class Exit: ICommandAction
{ {
if (args is null || args.Length == 0) if (args is null || args.Length == 0)
{ {
Application.CurrentApplication.Logger.Log("Exiting...", this, LogType.Warning); Application.Logger.Log("Exiting...", this, LogType.Warning);
await Application.CurrentApplication.ApplicationEnvironmentVariables.SaveToFile(); await Application.CurrentApplication.ApplicationEnvironmentVariables.SaveToFile();
Environment.Exit(0); Environment.Exit(0);
} }
@@ -42,7 +42,7 @@ public class Exit: ICommandAction
case "-f": case "-f":
case "force": case "force":
Application.CurrentApplication.Logger.Log("Exiting (FORCE)...", this, LogType.Warning); Application.Logger.Log("Exiting (FORCE)...", this, LogType.Warning);
Environment.Exit(0); Environment.Exit(0);
break; break;

View File

@@ -86,7 +86,7 @@ internal static class PluginMethods
}catch(Exception ex) }catch(Exception ex)
{ {
Application.CurrentApplication.Logger.LogException(ex, typeof(PluginMethods), false); Application.Logger.LogException(ex, typeof(PluginMethods), false);
} finally } finally
{ {
await Application.CurrentApplication.InternalActionManager.Initialize(); await Application.CurrentApplication.InternalActionManager.Initialize();
@@ -226,12 +226,12 @@ internal static class PluginMethods
{ {
if (data.IsSuccess) if (data.IsSuccess)
{ {
Application.CurrentApplication.Logger.Log("Successfully loaded command : " + data.PluginName, LogType.Info, "\t\t > {Message}"); Application.Logger.Log("Successfully loaded command : " + data.PluginName, LogType.Info, "\t\t > {Message}");
} }
else else
{ {
Application.CurrentApplication.Logger.Log("Failed to load command : " + data.PluginName + " because " + data.ErrorMessage, Application.Logger.Log("Failed to load command : " + data.PluginName + " because " + data.ErrorMessage,
typeof(PluginMethods), LogType.Error typeof(PluginMethods), LogType.Error
); );
} }
@@ -242,11 +242,11 @@ internal static class PluginMethods
{ {
if (data.IsSuccess) if (data.IsSuccess)
{ {
Application.CurrentApplication.Logger.Log("Successfully loaded event : " + data.PluginName, LogType.Info, "\t\t > {Message}"); Application.Logger.Log("Successfully loaded event : " + data.PluginName, LogType.Info, "\t\t > {Message}");
} }
else else
{ {
Application.CurrentApplication.Logger.Log("Failed to load event : " + data.PluginName + " because " + data.ErrorMessage, Application.Logger.Log("Failed to load event : " + data.PluginName + " because " + data.ErrorMessage,
typeof(PluginMethods), LogType.Error typeof(PluginMethods), LogType.Error
); );
} }
@@ -258,11 +258,11 @@ internal static class PluginMethods
{ {
if (data.IsSuccess) if (data.IsSuccess)
{ {
Application.CurrentApplication.Logger.Log("Successfully loaded slash command : " + data.PluginName, LogType.Info, "\t\t > {Message}"); Application.Logger.Log("Successfully loaded slash command : " + data.PluginName, LogType.Info, "\t\t > {Message}");
} }
else else
{ {
Application.CurrentApplication.Logger.Log("Failed to load slash command : " + data.PluginName + " because " + data.ErrorMessage, Application.Logger.Log("Failed to load slash command : " + data.PluginName + " because " + data.ErrorMessage,
typeof(PluginMethods), LogType.Error typeof(PluginMethods), LogType.Error
); );
} }
@@ -274,11 +274,11 @@ internal static class PluginMethods
{ {
if (data.IsSuccess) if (data.IsSuccess)
{ {
Application.CurrentApplication.Logger.Log("Successfully loaded action : " + data.PluginName, LogType.Info, "\t\t > {Message}"); Application.Logger.Log("Successfully loaded action : " + data.PluginName, LogType.Info, "\t\t > {Message}");
} }
else else
{ {
Application.CurrentApplication.Logger.Log("Failed to load action : " + data.PluginName + " because " + data.ErrorMessage, Application.Logger.Log("Failed to load action : " + data.PluginName + " because " + data.ErrorMessage,
typeof(PluginMethods), LogType.Error typeof(PluginMethods), LogType.Error
); );
} }

View File

@@ -1,8 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
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;
@@ -45,15 +47,7 @@ namespace DiscordBot.Bot.Actions
var modules = DiscordBotCore.Application.CurrentApplication.GetLoadedCoreModules(); var modules = DiscordBotCore.Application.CurrentApplication.GetLoadedCoreModules();
foreach (var module in modules) foreach (var module in modules)
{ {
Type moduleType = module.Key; Application.Logger.Log("Module: " + module.Key.ModuleName, this, LogType.Info);
List<object> moduleList = module.Value;
Console.WriteLine($"Module Type: {moduleType.Name}");
foreach (dynamic mod in moduleList)
{
Console.WriteLine($"Module: {mod.Name}");
}
} }
} }

View File

@@ -128,13 +128,7 @@ public class Plugin: ICommandAction
case "load": case "load":
if (pluginsLoaded) if (pluginsLoaded)
{ {
Application.CurrentApplication.Logger.Log("Plugins already loaded", this, LogType.Warning); Application.Logger.Log("Plugins already loaded", this, LogType.Warning);
break;
}
if (Application.CurrentApplication.DiscordBotClient is null)
{
Application.CurrentApplication.Logger.Log("DiscordBot is null", this, LogType.Warning);
break; break;
} }

View File

@@ -10,7 +10,7 @@ namespace DiscordBot.Bot.Commands;
/// <summary> /// <summary>
/// The help command /// The help command
/// </summary> /// </summary>
internal class Help: DBCommand internal class Help: IDbCommand
{ {
/// <summary> /// <summary>
/// Command name /// Command name
@@ -32,7 +32,7 @@ internal class Help: DBCommand
/// <summary> /// <summary>
/// Check if the command require administrator to be executed /// Check if the command require administrator to be executed
/// </summary> /// </summary>
public bool requireAdmin => false; public bool RequireAdmin => false;
/// <summary> /// <summary>
/// The main body of the command /// The main body of the command
@@ -58,7 +58,7 @@ internal class Help: DBCommand
var normalCommands = ""; var normalCommands = "";
foreach (var cmd in PluginLoader.Commands) foreach (var cmd in PluginLoader.Commands)
if (cmd.requireAdmin) if (cmd.RequireAdmin)
adminCommands += cmd.Command + " "; adminCommands += cmd.Command + " ";
else else
normalCommands += cmd.Command + " "; normalCommands += cmd.Command + " ";

View File

@@ -9,11 +9,11 @@ using DiscordBotCore.Others;
namespace DiscordBot.Bot.Commands.SlashCommands; namespace DiscordBot.Bot.Commands.SlashCommands;
public class Help: DBSlashCommand public class Help: IDbSlashCommand
{ {
public string Name => "help"; public string Name => "help";
public string Description => "This command allows you to check all loaded commands"; public string Description => "This command allows you to check all loaded commands";
public bool canUseDM => true; public bool CanUseDm => true;
public bool HasInteraction => false; public bool HasInteraction => false;
@@ -55,7 +55,7 @@ public class Help: DBSlashCommand
return; return;
} }
embedBuilder.AddField("DM Usable:", slashCommand.canUseDM, true) embedBuilder.AddField("DM Usable:", slashCommand.CanUseDm, true)
.WithDescription(slashCommand.Description); .WithDescription(slashCommand.Description);
} }

View File

@@ -44,6 +44,6 @@ public static class Installer
await Application.CurrentApplication.ApplicationEnvironmentVariables.SaveToFile(); await Application.CurrentApplication.ApplicationEnvironmentVariables.SaveToFile();
Application.CurrentApplication.Logger.Log("Config Saved", typeof(Installer)); Application.Logger.Log("Config Saved", typeof(Installer));
} }
} }

View File

@@ -71,7 +71,7 @@ public class Program
} }
catch (Exception ex) catch (Exception ex)
{ {
Application.CurrentApplication.Logger.Log(ex.ToString(), typeof(Program), LogType.Critical); Application.Logger.Log(ex.ToString(), typeof(Program), LogType.Critical);
} }
} }
@@ -91,7 +91,7 @@ public class Program
return; return;
} }
Application.CurrentApplication.Logger.SetOutFunction(AnsiConsole.MarkupLine); Application.Logger.SetOutFunction(AnsiConsole.MarkupLine);
if (!Application.CurrentApplication.ApplicationEnvironmentVariables.ContainsKey("ServerID") || if (!Application.CurrentApplication.ApplicationEnvironmentVariables.ContainsKey("ServerID") ||

View File

@@ -6,12 +6,12 @@ using DiscordBotCore.Plugin;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordBotCore.Others.Exceptions; using DiscordBotCore.Others.Exceptions;
using DiscordBotCore.Interfaces.Logger;
using DiscordBotCore.Modules; using DiscordBotCore.Modules;
using System.Diagnostics; using DiscordBotCore.Interfaces.Modules;
using DiscordBotCore.Online.Helpers; using DiscordBotCore.Online.Helpers;
using DiscordBotCore.Others.Settings; using DiscordBotCore.Others.Settings;
@@ -39,32 +39,6 @@ namespace DiscordBotCore
public CustomSettingsDictionary ApplicationEnvironmentVariables { get; private set; } public CustomSettingsDictionary ApplicationEnvironmentVariables { get; private set; }
public InternalActionManager InternalActionManager { get; private set; } public InternalActionManager InternalActionManager { get; private set; }
public ILogger Logger
{
get
{
try
{
return _ModuleManager.GetModule<ILogger>();
}
catch (ModuleNotFoundException<ILogger> ex)
{
Console.WriteLine("No logger found");
Console.WriteLine("Not having a valid logger is NOT an option. The default module will be downloaded from the official repo.");
Console.WriteLine("Install the default one ? [y/n]");
ConsoleKey response = Console.ReadKey().Key;
if (response is ConsoleKey.Y)
{
Process.Start("DiscordBot", "--module-install LoggerModule");
}
Environment.Exit(0);
return null!;
}
}
}
public IPluginManager PluginManager { get; private set; } public IPluginManager PluginManager { get; private set; }
public Bot.App DiscordBotClient { get; internal set; } public Bot.App DiscordBotClient { get; internal set; }
@@ -88,9 +62,9 @@ namespace DiscordBotCore
CurrentApplication.ApplicationEnvironmentVariables = await CustomSettingsDictionary.CreateFromFile(_ConfigFile, true); CurrentApplication.ApplicationEnvironmentVariables = await CustomSettingsDictionary.CreateFromFile(_ConfigFile, true);
CurrentApplication.ApplicationEnvironmentVariables.Set("PluginFolder", _PluginsFolder); CurrentApplication.ApplicationEnvironmentVariables.Add("PluginFolder", _PluginsFolder);
CurrentApplication.ApplicationEnvironmentVariables.Set("ResourceFolder", _ResourcesFolder); CurrentApplication.ApplicationEnvironmentVariables.Add("ResourceFolder", _ResourcesFolder);
CurrentApplication.ApplicationEnvironmentVariables.Set("LogsFolder", _LogsFolder); CurrentApplication.ApplicationEnvironmentVariables.Add("LogsFolder", _LogsFolder);
CurrentApplication._ModuleManager = new ModuleManager(); CurrentApplication._ModuleManager = new ModuleManager();
@@ -117,7 +91,52 @@ namespace DiscordBotCore
} }
public IReadOnlyDictionary<Type, List<object>> GetLoadedCoreModules() => _ModuleManager.LoadedModules.AsReadOnly(); public static class 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]);
}
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]);
}
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]);
}
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]);
}
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]);
}
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]);
}
public static async void SetOutFunction(Action<string> outFunction)
{
var loggerModule = CurrentApplication._ModuleManager.GetModule(ModuleType.Logger);
await CurrentApplication._ModuleManager.InvokeMethod(loggerModule.Value, loggerModule.Key.MethodMapping["SetPrintFunction"], [outFunction]);
}
}
public ReadOnlyDictionary<ModuleData, IModule> GetLoadedCoreModules() => _ModuleManager.Modules.AsReadOnly();
public static string GetResourceFullPath(string path) public static string GetResourceFullPath(string path)
{ {

View File

@@ -107,7 +107,7 @@ public class App
if (arg.Message.Contains("401")) if (arg.Message.Contains("401"))
{ {
Application.CurrentApplication.ApplicationEnvironmentVariables.Remove("token"); Application.CurrentApplication.ApplicationEnvironmentVariables.Remove("token");
Application.CurrentApplication.Logger.Log("The token is invalid.", this, LogType.Critical); Application.Logger.Log("The token is invalid.", this, LogType.Critical);
await Application.CurrentApplication.ApplicationEnvironmentVariables.SaveToFile(); await Application.CurrentApplication.ApplicationEnvironmentVariables.SaveToFile();
await Task.Delay(3000); await Task.Delay(3000);
@@ -124,7 +124,7 @@ public class App
private Task LoggedIn() private Task LoggedIn()
{ {
Application.CurrentApplication.Logger.Log("Successfully Logged In", this); Application.Logger.Log("Successfully Logged In", this);
return Task.CompletedTask; return Task.CompletedTask;
} }
@@ -134,12 +134,12 @@ public class App
{ {
case LogSeverity.Error: case LogSeverity.Error:
case LogSeverity.Critical: case LogSeverity.Critical:
Application.CurrentApplication.Logger.Log(message.Message, this, LogType.Error); Application.Logger.Log(message.Message, this, LogType.Error);
break; break;
case LogSeverity.Info: case LogSeverity.Info:
case LogSeverity.Debug: case LogSeverity.Debug:
Application.CurrentApplication.Logger.Log(message.Message, this, LogType.Info); Application.Logger.Log(message.Message, this, LogType.Info);
break; break;

View File

@@ -51,12 +51,12 @@ internal class CommandHandler
throw new Exception("Failed to run command !"); throw new Exception("Failed to run command !");
if (arg.Channel is SocketDMChannel) if (arg.Channel is SocketDMChannel)
plugin.ExecuteDM(arg); plugin.ExecuteDm(arg);
else plugin.ExecuteServer(arg); else plugin.ExecuteServer(arg);
} }
catch (Exception ex) catch (Exception ex)
{ {
Application.CurrentApplication.Logger.LogException(ex, this); Application.Logger.LogException(ex, this);
} }
return Task.CompletedTask; return Task.CompletedTask;
@@ -91,7 +91,7 @@ internal class CommandHandler
await _commandService.ExecuteAsync(context, argPos, null); await _commandService.ExecuteAsync(context, argPos, null);
DBCommand? plugin; IDbCommand? plugin;
var cleanMessage = ""; var cleanMessage = "";
if (message.HasMentionPrefix(_client.CurrentUser, ref argPos)) if (message.HasMentionPrefix(_client.CurrentUser, ref argPos))
@@ -129,7 +129,7 @@ internal class CommandHandler
if (plugin is null) if (plugin is null)
return; return;
if (plugin.requireAdmin && !context.Message.Author.IsAdmin()) if (plugin.RequireAdmin && !context.Message.Author.IsAdmin())
return; return;
var split = cleanMessage.Split(' '); var split = cleanMessage.Split(' ');
@@ -140,19 +140,19 @@ internal class CommandHandler
DbCommandExecutingArguments cmd = new(context, cleanMessage, split[0], argsClean); DbCommandExecutingArguments cmd = new(context, cleanMessage, split[0], argsClean);
Application.CurrentApplication.Logger.Log( Application.Logger.Log(
$"User ({context.User.Username}) from Guild \"{context.Guild.Name}\" executed command \"{cmd.CleanContent}\"", $"User ({context.User.Username}) from Guild \"{context.Guild.Name}\" executed command \"{cmd.CleanContent}\"",
this, this,
LogType.Info LogType.Info
); );
if (context.Channel is SocketDMChannel) if (context.Channel is SocketDMChannel)
plugin.ExecuteDM(cmd); plugin.ExecuteDm(cmd);
else plugin.ExecuteServer(cmd); else plugin.ExecuteServer(cmd);
} }
catch (Exception ex) catch (Exception ex)
{ {
Application.CurrentApplication.Logger.LogException(ex, this); Application.Logger.LogException(ex, this);
} }
} }
} }

View File

@@ -3,7 +3,7 @@ using DiscordBotCore.Others;
namespace DiscordBotCore.Interfaces; namespace DiscordBotCore.Interfaces;
public interface DBCommand public interface IDbCommand
{ {
/// <summary> /// <summary>
/// Command to be executed /// Command to be executed
@@ -30,7 +30,7 @@ public interface DBCommand
/// <summary> /// <summary>
/// true if the command requre admin, otherwise false /// true if the command requre admin, otherwise false
/// </summary> /// </summary>
bool requireAdmin { get; } bool RequireAdmin { get; }
/// <summary> /// <summary>
/// The main body of the command. This is what is executed when user calls the command in Server /// The main body of the command. This is what is executed when user calls the command in Server
@@ -44,7 +44,7 @@ public interface DBCommand
/// The main body of the command. This is what is executed when user calls the command in DM /// The main body of the command. This is what is executed when user calls the command in DM
/// </summary> /// </summary>
/// <param name="args">The disocrd Context</param> /// <param name="args">The disocrd Context</param>
void ExecuteDM(DbCommandExecutingArguments args) void ExecuteDm(DbCommandExecutingArguments args)
{ {
} }
} }

View File

@@ -2,7 +2,7 @@
namespace DiscordBotCore.Interfaces; namespace DiscordBotCore.Interfaces;
public interface DBEvent public interface IDbEvent
{ {
/// <summary> /// <summary>
/// The name of the event /// The name of the event

View File

@@ -6,11 +6,11 @@ using Discord.WebSocket;
namespace DiscordBotCore.Interfaces; namespace DiscordBotCore.Interfaces;
public interface DBSlashCommand public interface IDbSlashCommand
{ {
string Name { get; } string Name { get; }
string Description { get; } string Description { get; }
bool canUseDM { get; } bool CanUseDm { get; }
bool HasInteraction { get; } bool HasInteraction { get; }
List<SlashCommandOptionBuilder> Options { get; } List<SlashCommandOptionBuilder> Options { get; }
@@ -18,7 +18,7 @@ public interface DBSlashCommand
void ExecuteServer(SocketSlashCommand context) void ExecuteServer(SocketSlashCommand context)
{ } { }
void ExecuteDM(SocketSlashCommand context) { } void ExecuteDm(SocketSlashCommand context) { }
Task ExecuteInteraction(SocketInteraction interaction) => Task.CompletedTask; Task ExecuteInteraction(SocketInteraction interaction) => Task.CompletedTask;
} }

View File

@@ -1,15 +0,0 @@
using DiscordBotCore.Others;
using System;
namespace DiscordBotCore.Interfaces.Logger
{
public interface ILogMessage
{
public string Message { get; protected set; }
public DateTime ThrowTime { get; protected set; }
public string SenderName { get; protected set; }
public LogType LogMessageType { get; protected set; }
}
}

View File

@@ -1,26 +0,0 @@
using DiscordBotCore.Interfaces.Modules;
using DiscordBotCore.Others;
using System;
namespace DiscordBotCore.Interfaces.Logger
{
public interface ILogger : IBaseModule
{
public struct FormattedMessage {
public string Message;
public LogType Type;
}
string LogMessageFormat { get; set; }
void Log(string message);
void Log(string message, LogType logType);
void Log(string message, LogType logType, string format);
void Log(string message, object Sender);
void Log(string message, object Sender, LogType type);
void LogException(Exception exception, object Sender, bool logFullStack = false);
void SetOutFunction(Action<string> outFunction);
}
}

View File

@@ -1,8 +0,0 @@
using System;
namespace DiscordBotCore.Interfaces.Modules
{
public interface IBaseModule
{
}
}

View File

@@ -2,10 +2,20 @@
namespace DiscordBotCore.Interfaces.Modules namespace DiscordBotCore.Interfaces.Modules
{ {
public interface IModule<T> where T : IBaseModule
public enum ModuleType
{ {
Logger,
Other
}
/// <summary>
/// Define a module.
/// </summary>
public interface IModule
{
public ModuleType ModuleType { get; }
public string Name { get; } public string Name { get; }
public T Module { get; }
public Task Initialize(); public Task Initialize();
} }
} }

View File

@@ -9,7 +9,6 @@ namespace DiscordBotCore.Interfaces.PluginManager
{ {
public string BaseUrl { get; set; } public string BaseUrl { get; set; }
public string Branch { get; set; } public string Branch { get; set; }
Task AppendPluginToDatabase(PluginInfo pluginData); Task AppendPluginToDatabase(PluginInfo pluginData);
Task CheckForUpdates(); Task CheckForUpdates();
Task ExecutePluginInstallScripts(List<OnlineScriptDependencyInfo> listOfDependencies); Task ExecutePluginInstallScripts(List<OnlineScriptDependencyInfo> listOfDependencies);
@@ -24,7 +23,6 @@ namespace DiscordBotCore.Interfaces.PluginManager
Task<bool> MarkPluginToUninstall(string pluginName); Task<bool> MarkPluginToUninstall(string pluginName);
Task RemovePluginFromDatabase(string pluginName); Task RemovePluginFromDatabase(string pluginName);
Task UninstallMarkedPlugins(); Task UninstallMarkedPlugins();
Task SetEnabledStatus(string pluginName, bool status); Task SetEnabledStatus(string pluginName, bool status);
} }
} }

View File

@@ -35,9 +35,9 @@ internal class Loader
} }
} }
await LoadEverythingOfType<DBEvent>(); await LoadEverythingOfType<IDbEvent>();
await LoadEverythingOfType<DBCommand>(); await LoadEverythingOfType<IDbCommand>();
await LoadEverythingOfType<DBSlashCommand>(); await LoadEverythingOfType<IDbSlashCommand>();
await LoadEverythingOfType<ICommandAction>(); await LoadEverythingOfType<ICommandAction>();
} }
@@ -60,9 +60,9 @@ internal class Loader
var pluginType = plugin switch var pluginType = plugin switch
{ {
DBEvent => PluginType.EVENT, IDbEvent => PluginType.EVENT,
DBCommand => PluginType.COMMAND, IDbCommand => PluginType.COMMAND,
DBSlashCommand => PluginType.SLASH_COMMAND, IDbSlashCommand => PluginType.SLASH_COMMAND,
ICommandAction => PluginType.ACTION, ICommandAction => PluginType.ACTION,
_ => PluginType.UNKNOWN _ => PluginType.UNKNOWN
}; };

View File

@@ -6,23 +6,24 @@ using System.Threading.Tasks;
using DiscordBotCore.Interfaces.Modules; using DiscordBotCore.Interfaces.Modules;
using System.Reflection; using System.Reflection;
using DiscordBotCore.Modules;
namespace DiscordBotCore.Loaders namespace DiscordBotCore.Loaders
{ {
internal class ModuleLoader internal class ModuleLoader
{ {
private readonly string _ModuleFolder; private readonly List<ModuleData> _ModuleData;
public ModuleLoader(string moduleFolder) public ModuleLoader(List<ModuleData> moduleFolder)
{ {
_ModuleFolder = moduleFolder; _ModuleData = moduleFolder;
Directory.CreateDirectory(moduleFolder);
} }
public Task LoadFileModules() public Task LoadFileModules()
{ {
var files = Directory.GetFiles(_ModuleFolder, "*.dll"); var paths = _ModuleData.Select(module => module.ModulePath);
foreach (var file in files)
foreach (var file in paths)
{ {
try try
{ {
@@ -37,20 +38,20 @@ namespace DiscordBotCore.Loaders
return Task.CompletedTask; return Task.CompletedTask;
} }
public Task<List<IModule<T>>> LoadModules<T>() where T : IBaseModule public Task<List<IModule>> LoadModules()
{ {
var moduleType = typeof(IModule<T>); var moduleType = typeof(IModule);
var moduleTypes = AppDomain.CurrentDomain.GetAssemblies() var moduleTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes()) .SelectMany(s => s.GetTypes())
.Where(p => moduleType.IsAssignableFrom(p) && !p.IsInterface); .Where(p => moduleType.IsAssignableFrom(p) && !p.IsInterface);
var modules = new List<IModule<T>>(); var modules = new List<IModule>();
foreach (var module in moduleTypes) foreach (var module in moduleTypes)
{ {
try try
{ {
var instance = (IModule<T>?)Activator.CreateInstance(module); var instance = (IModule?)Activator.CreateInstance(module);
if (instance == null) if (instance is null)
{ {
Console.WriteLine($"Error loading module {module.Name}: Could not create instance"); Console.WriteLine($"Error loading module {module.Name}: Could not create instance");
continue; continue;

View File

@@ -26,9 +26,9 @@ public class PluginLoader
public SlashCommandLoaded? OnSlashCommandLoaded; public SlashCommandLoaded? OnSlashCommandLoaded;
public ActionLoaded? OnActionLoaded; public ActionLoaded? OnActionLoaded;
public static List<DBCommand> Commands { get; private set; } = new List<DBCommand>(); public static List<IDbCommand> Commands { get; private set; } = new List<IDbCommand>();
public static List<DBEvent> Events { get; private set; } = new List<DBEvent>(); public static List<IDbEvent> Events { get; private set; } = new List<IDbEvent>();
public static List<DBSlashCommand> SlashCommands { get; private set; } = new List<DBSlashCommand>(); public static List<IDbSlashCommand> SlashCommands { get; private set; } = new List<IDbSlashCommand>();
public static List<ICommandAction> Actions { get; private set; } = new List<ICommandAction>(); public static List<ICommandAction> Actions { get; private set; } = new List<ICommandAction>();
public PluginLoader(DiscordSocketClient discordSocketClient) public PluginLoader(DiscordSocketClient discordSocketClient)
@@ -41,7 +41,7 @@ public class PluginLoader
if (_Client == null) if (_Client == null)
{ {
Application.CurrentApplication.Logger.Log("Discord client is null", this, LogType.Error); Application.Logger.Log("Discord client is null", this, LogType.Error);
return; return;
} }
@@ -50,7 +50,7 @@ public class PluginLoader
SlashCommands.Clear(); SlashCommands.Clear();
Actions.Clear(); Actions.Clear();
Application.CurrentApplication.Logger.Log("Loading plugins...", this); Application.Logger.Log("Loading plugins...", this);
var loader = new Loader(); var loader = new Loader();
@@ -62,7 +62,7 @@ public class PluginLoader
private void FileLoadedException(FileLoaderResult result) private void FileLoadedException(FileLoaderResult result)
{ {
Application.CurrentApplication.Logger.Log(result.ErrorMessage, this, LogType.Error); Application.Logger.Log(result.ErrorMessage, this, LogType.Error);
} }
private async void OnPluginLoaded(PluginLoadResultData result) private async void OnPluginLoaded(PluginLoadResultData result)
@@ -81,31 +81,31 @@ public class PluginLoader
break; break;
case PluginType.COMMAND: case PluginType.COMMAND:
Commands.Add((DBCommand)result.Plugin); Commands.Add((IDbCommand)result.Plugin);
OnCommandLoaded?.Invoke(result); OnCommandLoaded?.Invoke(result);
break; break;
case PluginType.EVENT: case PluginType.EVENT:
if (this.TryStartEvent((DBEvent)result.Plugin)) if (this.TryStartEvent((IDbEvent)result.Plugin))
{ {
Events.Add((DBEvent)result.Plugin); Events.Add((IDbEvent)result.Plugin);
OnEventLoaded?.Invoke(result); OnEventLoaded?.Invoke(result);
} }
break; break;
case PluginType.SLASH_COMMAND: case PluginType.SLASH_COMMAND:
if (await this.TryStartSlashCommand((DBSlashCommand)result.Plugin)) if (await this.TryStartSlashCommand((IDbSlashCommand)result.Plugin))
{ {
if(((DBSlashCommand)result.Plugin).HasInteraction) if(((IDbSlashCommand)result.Plugin).HasInteraction)
_Client.InteractionCreated += ((DBSlashCommand)result.Plugin).ExecuteInteraction; _Client.InteractionCreated += ((IDbSlashCommand)result.Plugin).ExecuteInteraction;
SlashCommands.Add((DBSlashCommand)result.Plugin); SlashCommands.Add((IDbSlashCommand)result.Plugin);
OnSlashCommandLoaded?.Invoke(result); OnSlashCommandLoaded?.Invoke(result);
} }
else else
Application.CurrentApplication.Logger.Log($"Failed to start slash command {result.PluginName}", this, LogType.Error); Application.Logger.Log($"Failed to start slash command {result.PluginName}", this, LogType.Error);
break; break;
case PluginType.UNKNOWN: case PluginType.UNKNOWN:
default: default:
Application.CurrentApplication.Logger.Log("Unknown plugin type", this, LogType.Error); Application.Logger.Log("Unknown plugin type", this, LogType.Error);
break; break;
} }
} }

View File

@@ -14,7 +14,7 @@ namespace DiscordBotCore.Loaders;
internal static class PluginLoaderExtensions internal static class PluginLoaderExtensions
{ {
internal static bool TryStartEvent(this PluginLoader pluginLoader, DBEvent? dbEvent) internal static bool TryStartEvent(this PluginLoader pluginLoader, IDbEvent? dbEvent)
{ {
try try
{ {
@@ -28,13 +28,13 @@ internal static class PluginLoaderExtensions
} }
catch (Exception e) catch (Exception e)
{ {
Application.CurrentApplication.Logger.Log($"Error starting event {dbEvent.Name}: {e.Message}", typeof(PluginLoader), LogType.Error); Application.Logger.Log($"Error starting event {dbEvent.Name}: {e.Message}", typeof(PluginLoader), LogType.Error);
Application.CurrentApplication.Logger.LogException(e, typeof(PluginLoader)); Application.Logger.LogException(e, typeof(PluginLoader));
return false; return false;
} }
} }
internal static async Task<bool> TryStartSlashCommand(this PluginLoader pluginLoader, DBSlashCommand? dbSlashCommand) internal static async Task<bool> TryStartSlashCommand(this PluginLoader pluginLoader, IDbSlashCommand? dbSlashCommand)
{ {
try try
{ {
@@ -53,7 +53,7 @@ internal static class PluginLoaderExtensions
builder.WithDescription(dbSlashCommand.Description); builder.WithDescription(dbSlashCommand.Description);
builder.Options = dbSlashCommand.Options; builder.Options = dbSlashCommand.Options;
if (dbSlashCommand.canUseDM) if (dbSlashCommand.CanUseDm)
builder.WithContextTypes(InteractionContextType.BotDm, InteractionContextType.Guild); builder.WithContextTypes(InteractionContextType.BotDm, InteractionContextType.Guild);
else else
builder.WithContextTypes(InteractionContextType.Guild); builder.WithContextTypes(InteractionContextType.Guild);
@@ -64,7 +64,7 @@ internal static class PluginLoaderExtensions
if (!result) if (!result)
{ {
Application.CurrentApplication.Logger.Log($"Failed to enable slash command {dbSlashCommand.Name} for guild {guildId}", typeof(PluginLoader), LogType.Error); Application.Logger.Log($"Failed to enable slash command {dbSlashCommand.Name} for guild {guildId}", typeof(PluginLoader), LogType.Error);
} }
} }
@@ -74,7 +74,7 @@ internal static class PluginLoaderExtensions
} }
catch (Exception e) catch (Exception e)
{ {
Application.CurrentApplication.Logger.Log($"Error starting slash command {dbSlashCommand.Name}: {e.Message}", typeof(PluginLoader), LogType.Error); Application.Logger.Log($"Error starting slash command {dbSlashCommand.Name}: {e.Message}", typeof(PluginLoader), LogType.Error);
return false; return false;
} }
} }
@@ -84,7 +84,7 @@ internal static class PluginLoaderExtensions
SocketGuild? guild = pluginLoader._Client.GetGuild(guildId); SocketGuild? guild = pluginLoader._Client.GetGuild(guildId);
if (guild is null) if (guild is null)
{ {
Application.CurrentApplication.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);
return false; return false;
} }

View File

@@ -0,0 +1,19 @@
using System.Collections.Generic;
namespace DiscordBotCore.Modules;
public class ModuleData
{
public string ModuleName { get; set; }
public string ModulePath { get; set; }
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)
{
ModuleName = moduleName;
ModulePath = modulePath;
MethodMapping = methodMapping;
IsEnabled = isEnabled;
}
}

View File

@@ -1,8 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordBotCore.Online; using DiscordBotCore.Online;
@@ -11,20 +8,24 @@ namespace DiscordBotCore.Modules
{ {
public class ModuleDownloader public class ModuleDownloader
{ {
private string _moduleName; private readonly string _ModuleName;
private readonly string _baseUrl = "https://raw.githubusercontent.com/andreitdr/SethPlugins/tests/Modules/"; private const string _BaseUrl = "https://raw.githubusercontent.com/andreitdr/SethPlugins/tests/Modules/";
private readonly string _moduleFolder = "./Data/Modules";
public ModuleDownloader(string moduleName) public ModuleDownloader(string moduleName)
{ {
_moduleName = moduleName; _ModuleName = moduleName;
} }
public async Task DownloadModule(IProgress<float> progressToWrite) public async Task DownloadModule(IProgress<float> progressToWrite)
{ {
Directory.CreateDirectory(_moduleFolder); string? moduleFolder = Application.CurrentApplication.ApplicationEnvironmentVariables.Get<string>("ModuleFolder");
string url = _baseUrl + _moduleName + ".dll";
await ServerCom.DownloadFileAsync(url, _moduleFolder + "/" + _moduleName + ".dll", progressToWrite); 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,61 +1,98 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using DiscordBotCore.Interfaces.Logger;
using DiscordBotCore.Interfaces.Modules; using DiscordBotCore.Interfaces.Modules;
using DiscordBotCore.Loaders; using DiscordBotCore.Loaders;
using DiscordBotCore.Others.Exceptions; using Newtonsoft.Json;
namespace DiscordBotCore.Modules namespace DiscordBotCore.Modules
{ {
internal class ModuleManager internal class ModuleManager
{ {
private static readonly string _BaseModuleFolder = "./Data/Modules"; private static readonly string _BaseModuleFolder = "./Data/Modules";
private static readonly string _BaseModuleConfig = "./Data/Resources/modules.json";
private readonly string _ModuleFolder; internal Dictionary<ModuleData, IModule> Modules { get; set; }
internal Dictionary<Type, List<object>> LoadedModules { get; }
public ModuleManager(string moduleFolder)
{
_ModuleFolder = moduleFolder;
LoadedModules = new Dictionary<Type, List<object>>();
}
public ModuleManager() public ModuleManager()
{ {
_ModuleFolder = Application.CurrentApplication.ApplicationEnvironmentVariables.Get<string>("ModuleFolder", _BaseModuleFolder); Application.CurrentApplication.ApplicationEnvironmentVariables.Get<string>("ModuleFolder", _BaseModuleFolder);
LoadedModules = new Dictionary<Type, List<object>>(); Modules = new Dictionary<ModuleData, IModule>();
} }
public T GetModule<T>() where T : IBaseModule public KeyValuePair<ModuleData, IModule> GetModule(string moduleName)
{ {
if(!LoadedModules.ContainsKey(typeof(T))) return Modules.FirstOrDefault(module => module.Key.ModuleName == moduleName);
throw new ModuleNotFoundException<T>(); }
if (!LoadedModules[typeof(T)].Any()) public KeyValuePair<ModuleData, IModule> GetModule(ModuleType moduleType)
throw new ModuleNotFoundException<T>(); {
return Modules.First(module => module.Value.ModuleType == moduleType);
IModule<T> module = (IModule<T>)LoadedModules[typeof(T)][0];
return module.Module;
} }
public async Task LoadModules() public async Task LoadModules()
{ {
ModuleLoader loader = new ModuleLoader(_ModuleFolder); string moduleConfigPath = Application.CurrentApplication.ApplicationEnvironmentVariables
await loader.LoadFileModules(); .Get<string>("ModuleConfig", _BaseModuleConfig);
string moduleConfigFile = await File.ReadAllTextAsync(moduleConfigPath);
List<ModuleData>? listOfModuleData = JsonConvert.DeserializeObject<List<ModuleData>>(moduleConfigFile);
var loggers = await loader.LoadModules<ILogger>(); if(listOfModuleData is null)
foreach (var logger in loggers) return;
if (!listOfModuleData.Any())
{ {
await logger.Initialize(); return;
Console.WriteLine("Module Loaded: " + logger.Name);
} }
LoadedModules.Add(typeof(ILogger), loggers.Cast<object>().ToList()); 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);
}
}
}
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
}
await Task.Run(() => method.Invoke(module, parameters));
}
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}");
}
await Task.Run(() => method.Invoke(module, parameters));
} }

View File

@@ -119,7 +119,7 @@ public class PluginManager : IPluginManager
{ {
if (await pluginUpdater.HasUpdate(plugin.PluginName)) if (await pluginUpdater.HasUpdate(plugin.PluginName))
{ {
Application.CurrentApplication.Logger.Log("Updating plugin: " + plugin.PluginName, this, LogType.Info); Application.Logger.Log("Updating plugin: " + plugin.PluginName, this, LogType.Info);
await pluginUpdater.UpdatePlugin(plugin.PluginName); await pluginUpdater.UpdatePlugin(plugin.PluginName);
} }
} }

View File

@@ -22,7 +22,7 @@ public class InternalActionManager
if (this.Actions.ContainsKey(action.ActionName)) if (this.Actions.ContainsKey(action.ActionName))
{ {
// This should never happen. If it does, log it and return // This should never happen. If it does, log it and return
Application.CurrentApplication.Logger.Log($"Action {action.ActionName} already exists", this, LogType.Error); Application.Logger.Log($"Action {action.ActionName} already exists", this, LogType.Error);
return; return;
} }
@@ -50,7 +50,7 @@ public class InternalActionManager
{ {
if (!Actions.ContainsKey(actionName)) if (!Actions.ContainsKey(actionName))
{ {
Application.CurrentApplication.Logger.Log($"Action {actionName} not found", this, LogType.Error); Application.Logger.Log($"Action {actionName} not found", this, LogType.Error);
return false; return false;
} }
@@ -58,7 +58,7 @@ public class InternalActionManager
{ {
if (Actions[actionName].RunType == InternalActionRunType.OnStartup) if (Actions[actionName].RunType == InternalActionRunType.OnStartup)
{ {
Application.CurrentApplication.Logger.Log($"Action {actionName} is not executable", this, LogType.Error); Application.Logger.Log($"Action {actionName} is not executable", this, LogType.Error);
return false; return false;
} }
@@ -67,7 +67,7 @@ public class InternalActionManager
} }
catch (Exception e) catch (Exception e)
{ {
Application.CurrentApplication.Logger.Log(e.Message, type: LogType.Error, Sender: this); Application.Logger.Log(e.Message, type: LogType.Error, sender: this);
return false; return false;
} }
} }

View File

@@ -105,7 +105,7 @@ public static class ArchiveManager
} }
catch (Exception ex) catch (Exception ex)
{ {
Application.CurrentApplication.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.Error); // Write the error to a file Application.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.Error); // Write the error to a file
await Task.Delay(100); await Task.Delay(100);
return await ReadFromPakAsync(fileName, archFile); return await ReadFromPakAsync(fileName, archFile);
} }
@@ -141,7 +141,7 @@ public static class ArchiveManager
} }
catch (Exception ex) catch (Exception ex)
{ {
Application.CurrentApplication.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.Error); Application.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.Error);
} }
currentZipFile++; currentZipFile++;
@@ -176,7 +176,7 @@ public static class ArchiveManager
} }
catch (Exception ex) catch (Exception ex)
{ {
Application.CurrentApplication.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.Error); Application.Logger.Log(ex.Message, typeof(ArchiveManager), LogType.Error);
} }
await Task.Delay(10); await Task.Delay(10);

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic; using System;
using System.Collections;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -35,14 +37,14 @@ public class CustomSettingsDictionary : CustomSettingsDictionaryBase<string, obj
public override List<T> GetList<T>(string key, List<T> defaultValue) public override List<T> GetList<T>(string key, List<T> defaultValue)
{ {
List<T> result = base.GetList(key, defaultValue); List<T> value = base.GetList(key, defaultValue);
if (_EnableAutoAddOnGetWithDefault && defaultValue.All(result.Contains)) if (_EnableAutoAddOnGetWithDefault && value.All(defaultValue.Contains))
{ {
Add(key, defaultValue); Add(key, defaultValue);
} }
return result; return value;
} }
public override async Task LoadFromFile() public override async Task LoadFromFile()
@@ -71,10 +73,20 @@ public class CustomSettingsDictionary : CustomSettingsDictionaryBase<string, obj
else if (kvp.Value is JArray nestedJArray) else if (kvp.Value is JArray nestedJArray)
{ {
dict[kvp.Key] = nestedJArray.ToObject<List<object>>(); dict[kvp.Key] = nestedJArray.ToObject<List<object>>();
} }
else else
{ {
if (kvp.Value.Type == JTokenType.Integer)
dict[kvp.Key] = kvp.Value.Value<int>();
else if (kvp.Value.Type == JTokenType.Float)
dict[kvp.Key] = kvp.Value.Value<float>();
else if (kvp.Value.Type == JTokenType.Boolean)
dict[kvp.Key] = kvp.Value.Value<bool>();
else if (kvp.Value.Type == JTokenType.String)
dict[kvp.Key] = kvp.Value.Value<string>();
else if (kvp.Value.Type == JTokenType.Date)
dict[kvp.Key] = kvp.Value.Value<DateTime>();
else
dict[kvp.Key] = kvp.Value; dict[kvp.Key] = kvp.Value;
} }
} }

View File

@@ -57,6 +57,27 @@ public abstract class CustomSettingsDictionaryBase<TKey,TValue> : ICustomSetting
return default; return default;
} }
public virtual IDictionary<TSubKey, TSubValue> GetDictionary<TSubKey, TSubValue>(TKey key)
{
if (_InternalDictionary.TryGetValue(key, out var value))
{
if (value is not IDictionary)
{
throw new Exception("The value is not a dictionary");
}
var dictionary = new Dictionary<TSubKey, TSubValue>();
foreach (DictionaryEntry item in (IDictionary)value)
{
dictionary.Add((TSubKey)Convert.ChangeType(item.Key, typeof(TSubKey)), (TSubValue)Convert.ChangeType(item.Value, typeof(TSubValue)));
}
return dictionary;
}
return new Dictionary<TSubKey, TSubValue>();
}
public virtual List<T> GetList<T>(TKey key, List<T> defaultValue) public virtual List<T> GetList<T>(TKey key, List<T> defaultValue)
{ {
if(_InternalDictionary.TryGetValue(key, out var value)) if(_InternalDictionary.TryGetValue(key, out var value))
@@ -67,9 +88,9 @@ public abstract class CustomSettingsDictionaryBase<TKey,TValue> : ICustomSetting
} }
var list = new List<T>(); var list = new List<T>();
foreach (var item in (IList)value) foreach (object? item in (IList)value)
{ {
list.Add(ConvertValue<T>(item)); list.Add((T)Convert.ChangeType(item, typeof(T)));
} }
return list; return list;
@@ -141,20 +162,4 @@ public abstract class CustomSettingsDictionaryBase<TKey,TValue> : ICustomSetting
public abstract Task SaveToFile(); public abstract Task SaveToFile();
public abstract Task LoadFromFile(); public abstract Task LoadFromFile();
protected virtual T? ConvertValue<T>(object value)
{
if (typeof(T) == typeof(ulong) && value is long longValue)
{
return (T)(object)Convert.ToUInt64(longValue);
}
if (typeof(T).IsEnum && value is string stringValue)
{
return (T)Enum.Parse(typeof(T), stringValue);
}
return (T)Convert.ChangeType(value, typeof(T));
}
} }

View File

@@ -1,16 +1,17 @@
using DiscordBotCore; using DiscordBotCore.Interfaces.Modules;
using DiscordBotCore.Interfaces.Logger; using DiscordBotCore.Others;
using DiscordBotCore.Interfaces.Modules;
namespace LoggerModule namespace LoggerModule
{ {
public class Entry : IModule<ILogger> public class Entry : IModule
{ {
public string Name => "LoggerModule"; public string Name => "LoggerModule";
public ModuleType ModuleType => ModuleType.Logger;
const string _LogFolder = "./Data/Logs/"; const string _LogFolder = "./Data/Logs/";
const string _LogFormat = "{ThrowTime} {SenderName} {Message}"; const string _LogFormat = "{ThrowTime} {SenderName} {Message}";
public ILogger Module { get; private set; } public ILogger Module { get; private set; } = null!;
public Task Initialize() public Task Initialize()
{ {
@@ -18,5 +19,20 @@ namespace LoggerModule
Module = logger; Module = logger;
return Task.CompletedTask; return Task.CompletedTask;
} }
public void SetOutFunction(Action<string> outFunction)
{
Module.SetOutFunction(outFunction);
}
public void LogMessage(string message) => Module.Log(message);
public void LogMessageWithTypeAndFormat(string message, LogType logType, string format) => Module.Log(message, logType, format);
public void LogMessageWithType(string message, LogType logType) => Module.Log(message, logType);
public void LogMessageWithSender(string message, object Sender) => Module.Log(message, Sender);
public void LogMessageWithTypeAndSender(string message, object Sender, LogType type) => Module.Log(message, Sender, type);
public void LogExceptionWithSenderAndFullStack(Exception exception, object Sender, bool logFullStack = false) => Module.LogException(exception, Sender, logFullStack);
} }
} }

View File

@@ -0,0 +1,12 @@
using DiscordBotCore.Others;
namespace LoggerModule;
public interface ILogMessage
{
public string Message { get; protected set; }
public DateTime ThrowTime { get; protected set; }
public string SenderName { get; protected set; }
public LogType LogMessageType { get; protected set; }
}

View File

@@ -0,0 +1,22 @@
using DiscordBotCore.Others;
namespace LoggerModule;
public interface ILogger
{
public struct FormattedMessage {
public string Message;
public LogType Type;
}
string LogMessageFormat { get; set; }
void Log(string message);
void Log(string message, LogType logType);
void Log(string message, LogType logType, string format);
void Log(string message, object Sender);
void Log(string message, object Sender, LogType type);
void LogException(Exception exception, object Sender, bool logFullStack = false);
void SetOutFunction(Action<string> outFunction);
}

View File

@@ -1,5 +1,4 @@
using DiscordBotCore.Interfaces.Logger; using DiscordBotCore.Others;
using DiscordBotCore.Others;
namespace LoggerModule namespace LoggerModule
{ {

View File

@@ -1,5 +1,4 @@
using DiscordBotCore.Interfaces.Logger; using DiscordBotCore.Others;
using DiscordBotCore.Others;
namespace LoggerModule; namespace LoggerModule;

View File

@@ -21,7 +21,7 @@ namespace CppWrapper.LibraryManagement
return; return;
} }
Application.CurrentApplication.Logger.Log($"Loading library {LibraryPath}"); Application.Logger.Log($"Loading library {LibraryPath}");
if(!NativeLibrary.TryLoad(LibraryPath, out IntPtr hModule)) if(!NativeLibrary.TryLoad(LibraryPath, out IntPtr hModule))
@@ -29,7 +29,7 @@ namespace CppWrapper.LibraryManagement
throw new DllNotFoundException($"Unable to load library {LibraryPath}"); throw new DllNotFoundException($"Unable to load library {LibraryPath}");
} }
Application.CurrentApplication.Logger.Log($"Library {LibraryPath} loaded successfully [{hModule}]"); Application.Logger.Log($"Library {LibraryPath} loaded successfully [{hModule}]");
LibraryHandle = hModule; LibraryHandle = hModule;
} }
@@ -44,7 +44,7 @@ namespace CppWrapper.LibraryManagement
NativeLibrary.Free(LibraryHandle); NativeLibrary.Free(LibraryHandle);
LibraryHandle = IntPtr.Zero; LibraryHandle = IntPtr.Zero;
Application.CurrentApplication.Logger.Log($"Library {LibraryPath} freed successfully"); Application.Logger.Log($"Library {LibraryPath} freed successfully");
} }
private IntPtr GetFunctionPointer(string functionName) private IntPtr GetFunctionPointer(string functionName)
@@ -66,11 +66,11 @@ namespace CppWrapper.LibraryManagement
{ {
IntPtr functionPointer = GetFunctionPointer(methodName); IntPtr functionPointer = GetFunctionPointer(methodName);
Application.CurrentApplication.Logger.Log($"Function pointer for {methodName} obtained successfully [address: {functionPointer}]"); Application.Logger.Log($"Function pointer for {methodName} obtained successfully [address: {functionPointer}]");
T result = (T)Marshal.GetDelegateForFunctionPointer(functionPointer, typeof(T)); T result = (T)Marshal.GetDelegateForFunctionPointer(functionPointer, typeof(T));
Application.CurrentApplication.Logger.Log($"Delegate for {methodName} created successfully"); Application.Logger.Log($"Delegate for {methodName} created successfully");
return result; return result;
} }
@@ -79,7 +79,7 @@ namespace CppWrapper.LibraryManagement
{ {
IntPtr functionPointer = Marshal.GetFunctionPointerForDelegate(functionDelegate); IntPtr functionPointer = Marshal.GetFunctionPointerForDelegate(functionDelegate);
Application.CurrentApplication.Logger.Log($"Function pointer for delegate {functionDelegate.Method.Name} obtained successfully [address: {functionPointer}]"); Application.Logger.Log($"Function pointer for delegate {functionDelegate.Method.Name} obtained successfully [address: {functionPointer}]");
return functionPointer; return functionPointer;
} }
@@ -104,7 +104,7 @@ namespace CppWrapper.LibraryManagement
var result = setterDelegate.DynamicInvoke(executableFunctionPtr); var result = setterDelegate.DynamicInvoke(executableFunctionPtr);
Application.CurrentApplication.Logger.Log($"Function {setterExternFunctionName} bound to local action successfully"); Application.Logger.Log($"Function {setterExternFunctionName} bound to local action successfully");
return result; return result;
} }

View File

@@ -48,7 +48,7 @@ public class Entry : ICommandAction
externalLibrary.FreeLibrary(); externalLibrary.FreeLibrary();
} catch (Exception dllException) { } catch (Exception dllException) {
Application.CurrentApplication.Logger.LogException(dllException, this); Application.Logger.LogException(dllException, this);
} }
} }
} }

View File

@@ -5,7 +5,7 @@ using DiscordBotCore.Others;
namespace LevelingSystem; namespace LevelingSystem;
internal class LevelCommand: DBCommand internal class LevelCommand: IDbCommand
{ {
public string Command => "level"; public string Command => "level";
@@ -15,13 +15,13 @@ internal class LevelCommand: DBCommand
public string Usage => "level"; public string Usage => "level";
public bool requireAdmin => false; public bool RequireAdmin => false;
public async void ExecuteServer(DbCommandExecutingArguments args) public async void ExecuteServer(DbCommandExecutingArguments args)
{ {
if(Variables.Database is null) if(Variables.Database is null)
{ {
Application.CurrentApplication.Logger.Log("Database is not initialized", this, LogType.Warning); Application.Logger.Log("Database is not initialized", this, LogType.Warning);
return; return;
} }

View File

@@ -7,7 +7,7 @@ using static LevelingSystem.Variables;
namespace LevelingSystem; namespace LevelingSystem;
internal class LevelEvent : DBEvent internal class LevelEvent : IDbEvent
{ {
public string Name => "Leveling System Event Handler"; public string Name => "Leveling System Event Handler";
public string Description => "The Leveling System Event Handler"; public string Description => "The Leveling System Event Handler";

View File

@@ -7,7 +7,7 @@ using DiscordBotCore.Others;
namespace MusicPlayer.Commands; namespace MusicPlayer.Commands;
public class AddMelody: DBCommand public class AddMelody: IDbCommand
{ {
public string Command => "add_melody"; public string Command => "add_melody";
@@ -18,7 +18,7 @@ public class AddMelody: DBCommand
public string Description => "Add a custom melody to the database"; public string Description => "Add a custom melody to the database";
public string Usage => "add_melody [title],[description?],[aliases],[byteSize]"; public string Usage => "add_melody [title],[description?],[aliases],[byteSize]";
public bool requireAdmin => false; public bool RequireAdmin => false;
public async void ExecuteServer(DbCommandExecutingArguments args) public async void ExecuteServer(DbCommandExecutingArguments args)
{ {

View File

@@ -6,7 +6,7 @@ using DiscordBotCore.Others;
namespace MusicPlayer.Commands; namespace MusicPlayer.Commands;
public class AddMelodyYoutube: DBCommand public class AddMelodyYoutube: IDbCommand
{ {
public string Command => "add_melody_youtube"; public string Command => "add_melody_youtube";
@@ -17,7 +17,7 @@ public class AddMelodyYoutube: DBCommand
public string Description => "Add melody to the database from a youtube link"; public string Description => "Add melody to the database from a youtube link";
public string Usage => "add_melody_youtube [URL] <alias1|alias2|...>"; public string Usage => "add_melody_youtube [URL] <alias1|alias2|...>";
public bool requireAdmin => true; public bool RequireAdmin => true;
public async void ExecuteServer(DbCommandExecutingArguments args) public async void ExecuteServer(DbCommandExecutingArguments args)
{ {

View File

@@ -4,14 +4,14 @@ using DiscordBotCore.Others;
namespace MusicPlayer.Commands; namespace MusicPlayer.Commands;
public class SearchMelody: DBCommand public class SearchMelody: IDbCommand
{ {
public string Command => "search_melody"; public string Command => "search_melody";
public List<string>? Aliases => null; public List<string>? Aliases => null;
public string Description => "Search for a melody in the database"; public string Description => "Search for a melody in the database";
public string Usage => "search_melody [melody name OR one of its aliases]"; public string Usage => "search_melody [melody name OR one of its aliases]";
public bool requireAdmin => false; public bool RequireAdmin => false;
public void ExecuteServer(DbCommandExecutingArguments args) public void ExecuteServer(DbCommandExecutingArguments args)
{ {

View File

@@ -5,7 +5,7 @@ using DiscordBotCore.Interfaces;
namespace MusicPlayer.Events; namespace MusicPlayer.Events;
public class OnLoad: DBEvent public class OnLoad: IDbEvent
{ {
private static readonly string _DefaultMusicPath = "Music/"; private static readonly string _DefaultMusicPath = "Music/";
private static readonly string _DefaultSaveLocation = "Music/Melodies/"; private static readonly string _DefaultSaveLocation = "Music/Melodies/";

View File

@@ -5,7 +5,7 @@ using DiscordBotCore.Others;
namespace MusicPlayer.Events; namespace MusicPlayer.Events;
public class OnVoiceRemoved: DBEvent public class OnVoiceRemoved: IDbEvent
{ {
public string Name => "Event: OnVoiceRemoved"; public string Name => "Event: OnVoiceRemoved";
@@ -24,7 +24,7 @@ public class OnVoiceRemoved: DBEvent
Variables.audioClient = null; Variables.audioClient = null;
Variables._MusicPlayer = null; Variables._MusicPlayer = null;
Application.CurrentApplication.Logger.Log("Bot left voice channel.", this, LogType.Info); Application.Logger.Log("Bot left voice channel.", this, LogType.Info);
} }
}; };

View File

@@ -29,13 +29,13 @@ public class MusicPlayer
{ {
if (isQueueRunning) if (isQueueRunning)
{ {
Application.CurrentApplication.Logger.Log("Another queue is running !", typeof(MusicPlayer), LogType.Warning); Application.Logger.Log("Another queue is running !", typeof(MusicPlayer), LogType.Warning);
return; return;
} }
if (Variables.audioClient is null) if (Variables.audioClient is null)
{ {
Application.CurrentApplication.Logger.Log("Audio Client is null", typeof(MusicPlayer), LogType.Warning); Application.Logger.Log("Audio Client is null", typeof(MusicPlayer), LogType.Warning);
return; return;
} }
@@ -44,7 +44,7 @@ public class MusicPlayer
string? ffmpegPath = await Application.CurrentApplication.PluginManager.GetDependencyLocation("FFMPEG"); string? ffmpegPath = await Application.CurrentApplication.PluginManager.GetDependencyLocation("FFMPEG");
if(ffmpegPath is null) if(ffmpegPath is null)
{ {
Application.CurrentApplication.Logger.Log("FFMPEG is missing. Please install it and try again.", typeof(MusicPlayer), LogType.Error); Application.Logger.Log("FFMPEG is missing. Please install it and try again.", typeof(MusicPlayer), LogType.Error);
isQueueRunning = false; isQueueRunning = false;
return; return;
} }
@@ -61,7 +61,7 @@ public class MusicPlayer
using var ffmpeg = CreateStream(ffmpegPath, CurrentlyPlaying.Location); using var ffmpeg = CreateStream(ffmpegPath, CurrentlyPlaying.Location);
if (ffmpeg is null) if (ffmpeg is null)
{ {
Application.CurrentApplication.Logger.Log($"Failed to start ffmpeg process. FFMPEG is missing or the {CurrentlyPlaying.Location} has an invalid format.", typeof(MusicPlayer), LogType.Error); Application.Logger.Log($"Failed to start ffmpeg process. FFMPEG is missing or the {CurrentlyPlaying.Location} has an invalid format.", typeof(MusicPlayer), LogType.Error);
continue; continue;
} }
await using var ffmpegOut = ffmpeg.StandardOutput.BaseStream; await using var ffmpegOut = ffmpeg.StandardOutput.BaseStream;
@@ -111,7 +111,7 @@ public class MusicPlayer
} }
catch (Exception ex) catch (Exception ex)
{ {
Application.CurrentApplication.Logger.LogException(ex, this); Application.Logger.LogException(ex, this);
break; break;
} }
} }

View File

@@ -4,12 +4,12 @@ using DiscordBotCore.Interfaces;
namespace MusicPlayer.SlashCommands; namespace MusicPlayer.SlashCommands;
public class Loop: DBSlashCommand public class Loop: IDbSlashCommand
{ {
public string Name => "loop"; public string Name => "loop";
public string Description => "Loop the current song for a certain amount of times. If no times are specified, it will loop once"; public string Description => "Loop the current song for a certain amount of times. If no times are specified, it will loop once";
public bool canUseDM => false; public bool CanUseDm => false;
public bool HasInteraction => false; public bool HasInteraction => false;
public List<SlashCommandOptionBuilder> Options => new() public List<SlashCommandOptionBuilder> Options => new()

View File

@@ -7,11 +7,11 @@ using DiscordBotCore.Others;
namespace MusicPlayer.SlashCommands; namespace MusicPlayer.SlashCommands;
public class Play: DBSlashCommand public class Play: IDbSlashCommand
{ {
public string Name => "play"; public string Name => "play";
public string Description => "Play music command"; public string Description => "Play music command";
public bool canUseDM => false; public bool CanUseDm => false;
public bool HasInteraction => false; public bool HasInteraction => false;
public List<SlashCommandOptionBuilder> Options => new() public List<SlashCommandOptionBuilder> Options => new()
@@ -55,7 +55,7 @@ public class Play: DBSlashCommand
if (user is null) if (user is null)
{ {
await context.RespondAsync("Failed to get user data from channel ! Check error log at " + DateTime.Now.ToLongTimeString()); await context.RespondAsync("Failed to get user data from channel ! Check error log at " + DateTime.Now.ToLongTimeString());
Application.CurrentApplication.Logger.Log("User is null while trying to convert from context.User to IGuildUser.", typeof(Play), LogType.Error); Application.Logger.Log("User is null while trying to convert from context.User to IGuildUser.", typeof(Play), LogType.Error);
return; return;
} }

View File

@@ -4,11 +4,11 @@ using DiscordBotCore.Interfaces;
namespace MusicPlayer.SlashCommands; namespace MusicPlayer.SlashCommands;
public class Queue: DBSlashCommand public class Queue: IDbSlashCommand
{ {
public string Name => "queue"; public string Name => "queue";
public string Description => "Queue a melody to play"; public string Description => "Queue a melody to play";
public bool canUseDM => false; public bool CanUseDm => false;
public bool HasInteraction => false; public bool HasInteraction => false;
public List<SlashCommandOptionBuilder> Options => null; public List<SlashCommandOptionBuilder> Options => null;

View File

@@ -4,11 +4,11 @@ using DiscordBotCore.Interfaces;
namespace MusicPlayer.SlashCommands; namespace MusicPlayer.SlashCommands;
public class Skip: DBSlashCommand public class Skip: IDbSlashCommand
{ {
public string Name => "skip"; public string Name => "skip";
public string Description => "Skip the current melody"; public string Description => "Skip the current melody";
public bool canUseDM => false; public bool CanUseDm => false;
public bool HasInteraction => false; public bool HasInteraction => false;
public List<SlashCommandOptionBuilder> Options => null; public List<SlashCommandOptionBuilder> Options => null;