Formatted code and rebuilt PluginLoader

This commit is contained in:
2024-02-27 11:07:27 +02:00
parent 14f280baef
commit ef7a2c0896
40 changed files with 525 additions and 524 deletions

View File

@@ -0,0 +1,20 @@
namespace PluginManager.Loaders;
public class FileLoaderResult
{
public string PluginName { get; init; }
public string? ErrorMessage { get; init; }
public FileLoaderResult(string pluginName, string errorMessage)
{
PluginName = pluginName;
ErrorMessage = errorMessage;
}
public FileLoaderResult(string pluginName)
{
PluginName = pluginName;
}
}

View File

@@ -1,52 +1,40 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using PluginManager.Interfaces;
using PluginManager.Others;
namespace PluginManager.Loaders;
internal class LoaderArgs: EventArgs
{
internal string? PluginName { get; init; }
internal string? TypeName { get; init; }
internal bool IsLoaded { get; init; }
internal Exception? Exception { get; init; }
internal object? Plugin { get; init; }
}
internal class Loader
{
internal Loader(string path, string extension)
private readonly string _SearchPath;
private readonly string _FileExtension;
internal delegate void FileLoadedHandler(FileLoaderResult result);
internal delegate void PluginLoadedHandler(PluginLoadResultData result);
internal event FileLoadedHandler? OnFileLoadedException;
internal event PluginLoadedHandler? OnPluginLoaded;
internal Loader(string searchPath, string fileExtension)
{
this.Path = path;
this.Extension = extension;
_SearchPath = searchPath;
_FileExtension = fileExtension;
}
private string Path { get; }
private string Extension { get; }
internal event FileLoadedEventHandler? FileLoaded;
internal event PluginLoadedEventHandler? PluginLoaded;
internal (List<DBEvent>?, List<DBCommand>?, List<DBSlashCommand>?) Load()
internal async Task Load()
{
List<DBEvent> events = new();
List<DBSlashCommand> slashCommands = new();
List<DBCommand> commands = new();
if (!Directory.Exists(Path))
if (!Directory.Exists(_SearchPath))
{
Directory.CreateDirectory(Path);
return (null, null, null);
Directory.CreateDirectory(_SearchPath);
return;
}
var files = Directory.GetFiles(Path, $"*.{Extension}", SearchOption.AllDirectories);
var files = Directory.GetFiles(_SearchPath, $"*.{_FileExtension}", SearchOption.TopDirectoryOnly);
foreach (var file in files)
{
try
@@ -55,91 +43,40 @@ internal class Loader
}
catch
{
Config.Logger.Log("PluginName: " + new FileInfo(file).Name.Split('.')[0] + " not loaded", source: typeof(Loader), type: LogType.ERROR);
continue;
}
if (FileLoaded != null)
{
var args = new LoaderArgs
{
Exception = null,
TypeName = null,
IsLoaded = false,
PluginName = new FileInfo(file).Name.Split('.')[0],
Plugin = null
};
FileLoaded.Invoke(args);
OnFileLoadedException?.Invoke(new FileLoaderResult(file, "Failed to load file"));
}
}
return (LoadItems<DBEvent>(), LoadItems<DBCommand>(), LoadItems<DBSlashCommand>());
await LoadEverythingOfType<DBEvent>();
await LoadEverythingOfType<DBCommand>();
await LoadEverythingOfType<DBSlashCommand>();
}
internal List<T> LoadItems<T>()
private async Task LoadEverythingOfType<T>()
{
List<T> list = new();
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => typeof(T).IsAssignableFrom(p) && !p.IsInterface);
try
foreach (var type in types)
{
var interfaceType = typeof(T);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.GetTypes())
.Where(p => interfaceType.IsAssignableFrom(p) && p.IsClass)
.ToArray();
list.Clear();
foreach (var type in types)
try
try
{
var plugin = (T)Activator.CreateInstance(type);
var pluginType = plugin switch
{
var plugin = (T)Activator.CreateInstance(type)!;
list.Add(plugin);
if (PluginLoaded != null)
PluginLoaded.Invoke(new LoaderArgs
{
Exception = null,
IsLoaded = true,
PluginName = type.FullName,
TypeName = typeof(T) == typeof(DBCommand) ? "DBCommand" :
typeof(T) == typeof(DBEvent) ? "DBEvent" :
typeof(T) == typeof(DBSlashCommand) ? "DBSlashCommand" :
null,
Plugin = plugin
}
);
}
catch (Exception ex)
{
if (PluginLoaded != null)
PluginLoaded.Invoke(new LoaderArgs
{
Exception = ex,
IsLoaded = false,
PluginName = type.FullName,
TypeName = nameof(T)
}
);
}
return list;
DBEvent => PluginType.EVENT,
DBCommand => PluginType.COMMAND,
DBSlashCommand => PluginType.SLASH_COMMAND,
_ => PluginType.UNKNOWN
};
OnPluginLoaded?.Invoke(new PluginLoadResultData(type.FullName, pluginType, true, plugin: plugin));
}
catch (Exception ex)
{
OnPluginLoaded?.Invoke(new PluginLoadResultData(type.FullName, PluginType.UNKNOWN, false, ex.Message));
}
}
catch (Exception ex)
{
Config.Logger.Log(ex.Message, source: typeof(Loader), type: LogType.ERROR);
return null;
}
return null;
}
internal delegate void FileLoadedEventHandler(LoaderArgs args);
internal delegate void PluginLoadedEventHandler(LoaderArgs args);
}

View File

@@ -0,0 +1,6 @@
namespace PluginManager.Loaders;
public class PluginHandler
{
}

View File

@@ -0,0 +1,22 @@
using PluginManager.Others;
namespace PluginManager.Loaders;
public class PluginLoadResultData
{
public string PluginName { get; init; }
public PluginType PluginType { get; init; }
public string? ErrorMessage { get; init; }
public bool IsSuccess { get; init; }
public object? Plugin { get; init; }
public PluginLoadResultData(string pluginName, PluginType pluginType, bool isSuccess, string? errorMessage = null, object plugin = null)
{
PluginName = pluginName;
PluginType = pluginType;
IsSuccess = isSuccess;
ErrorMessage = errorMessage;
Plugin = plugin;
}
}

View File

@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;
using PluginManager.Interfaces;
using PluginManager.Others;
@@ -11,173 +8,78 @@ namespace PluginManager.Loaders;
public class PluginLoader
{
public delegate void CMDLoaded(string name, string typeName, bool success, Exception? e = null);
internal readonly DiscordSocketClient _Client;
public delegate void EVELoaded(string name, string typeName, bool success, Exception? e = null);
public delegate void CommandLoaded(PluginLoadResultData resultData);
public delegate void SLSHLoaded(string name, string tyypename, bool success, Exception? e = null);
public delegate void EventLoaded(PluginLoadResultData resultData);
private const string pluginFolder = @"./Data/Plugins/";
public delegate void SlashCommandLoaded(PluginLoadResultData resultData);
internal const string pluginExtension = "dll";
private readonly DiscordSocketClient _client;
public CommandLoaded? OnCommandLoaded;
public EventLoaded? OnEventLoaded;
public SlashCommandLoaded? OnSlashCommandLoaded;
/// <summary>
/// Event that is fired when a <see cref="DBCommand" /> is successfully loaded into commands list
/// </summary>
public CMDLoaded? onCMDLoad;
public static List<DBCommand>? Commands;
public static List<DBEvent>? Events;
public static List<DBSlashCommand>? SlashCommands;
/// <summary>
/// Event that is fired when a <see cref="DBEvent" /> is successfully loaded into events list
/// </summary>
public EVELoaded? onEVELoad;
/// <summary>
/// Event that is fired when a <see cref="DBEvent" /> is successfully loaded into events list
/// </summary>
public SLSHLoaded? onSLSHLoad;
/// <summary>
/// The Plugin Loader constructor
/// </summary>
/// <param name="discordSocketClient">The discord bot client where the plugins will pe attached to</param>
public PluginLoader(DiscordSocketClient discordSocketClient)
{
_client = discordSocketClient;
_Client = discordSocketClient;
}
/// <summary>
/// A list of <see cref="DBCommand" /> commands
/// </summary>
public static List<DBCommand>? Commands { get; set; }
/// <summary>
/// A list of <see cref="DBEvent" /> commands
/// </summary>
public static List<DBEvent>? Events { get; set; }
/// <summary>
/// A list of <see cref="DBSlashCommand" /> commands
/// </summary>
public static List<DBSlashCommand>? SlashCommands { get; set; }
public static int PluginsLoaded
public async Task LoadPlugins()
{
get
{
var count = 0;
if (Commands is not null)
count += Commands.Count;
if (Events is not null)
count += Events.Count;
if (SlashCommands is not null)
count += SlashCommands.Count;
return count;
}
}
/// <summary>
/// The main mathod that is called to load all events
/// </summary>
public async void LoadPlugins()
{
//Load all plugins
Commands = new List<DBCommand>();
Events = new List<DBEvent>();
SlashCommands = new List<DBSlashCommand>();
Config.Logger.Log("Starting plugin loader ... Client: " + _client.CurrentUser.Username, source: typeof(PluginLoader), type: LogType.INFO);
Config.Logger.Log("Loading plugins...", typeof(PluginLoader));
var loader = new Loader("./Data/Plugins", "dll");
loader.FileLoaded += args => Config.Logger.Log($"{args.PluginName} file Loaded", source: typeof(PluginLoader), type: LogType.INFO);
loader.PluginLoaded += Loader_PluginLoaded;
var res = loader.Load();
Events = res.Item1;
Commands = res.Item2;
SlashCommands = res.Item3;
var loader = new Loader(Config.AppSettings["PluginFolder"], "dll");
loader.OnFileLoadedException += FileLoadedException;
loader.OnPluginLoaded += OnPluginLoaded;
await loader.Load();
}
private async void Loader_PluginLoaded(LoaderArgs args)
private void FileLoadedException(FileLoaderResult result)
{
switch (args.TypeName)
Config.Logger.Log(result.ErrorMessage, typeof(PluginLoader), LogType.ERROR);
}
private void OnPluginLoaded(PluginLoadResultData result)
{
switch (result.PluginType)
{
case "DBCommand":
onCMDLoad?.Invoke(((DBCommand)args.Plugin!).Command, args.TypeName!, args.IsLoaded, args.Exception);
case PluginType.COMMAND:
Commands.Add((DBCommand)result.Plugin);
OnCommandLoaded?.Invoke(result);
break;
case "DBEvent":
try
case PluginType.EVENT:
if (this.TryStartEvent((DBEvent)result.Plugin))
{
if (args.IsLoaded)
((DBEvent)args.Plugin!).Start(_client);
onEVELoad?.Invoke(((DBEvent)args.Plugin!).Name, args.TypeName!, args.IsLoaded, args.Exception);
}
catch (Exception ex)
{
Config.Logger.Log(ex.Message, source: typeof(PluginLoader), type: LogType.ERROR);
Events.Add((DBEvent)result.Plugin);
OnEventLoaded?.Invoke(result);
}
break;
case "DBSlashCommand":
if (args.IsLoaded)
case PluginType.SLASH_COMMAND:
if (this.TryStartSlashCommand((DBSlashCommand)result.Plugin))
{
var slash = (DBSlashCommand)args.Plugin;
var builder = new SlashCommandBuilder();
builder.WithName(slash.Name);
builder.WithDescription(slash.Description);
builder.WithDMPermission(slash.canUseDM);
builder.Options = slash.Options;
onSLSHLoad?.Invoke(((DBSlashCommand)args.Plugin!).Name, args.TypeName, args.IsLoaded,
args.Exception
);
await _client.CreateGlobalApplicationCommandAsync(builder.Build());
SlashCommands.Add((DBSlashCommand)result.Plugin);
OnSlashCommandLoaded?.Invoke(result);
}
break;
case PluginType.UNKNOWN:
default:
Config.Logger.Log("Unknown plugin type", typeof(PluginLoader), LogType.ERROR);
break;
}
}
public static async Task LoadPluginFromAssembly(Assembly asmb, DiscordSocketClient client)
{
var types = asmb.GetTypes();
foreach (var type in types)
try
{
if (type.IsClass && typeof(DBEvent).IsAssignableFrom(type))
{
var instance = (DBEvent)Activator.CreateInstance(type);
instance.Start(client);
Events.Add(instance);
Config.Logger.Log($"[EVENT] Loaded external {type.FullName}!", source: typeof(PluginLoader));
}
else if (type.IsClass && typeof(DBCommand).IsAssignableFrom(type))
{
var instance = (DBCommand)Activator.CreateInstance(type);
Commands.Add(instance);
Config.Logger.Log($"[CMD] Instance: {type.FullName} loaded !", source: typeof(PluginLoader));
}
else if (type.IsClass && typeof(DBSlashCommand).IsAssignableFrom(type))
{
var instance = (DBSlashCommand)Activator.CreateInstance(type);
var builder = new SlashCommandBuilder();
builder.WithName(instance.Name);
builder.WithDescription(instance.Description);
builder.WithDMPermission(instance.canUseDM);
builder.Options = instance.Options;
await client.CreateGlobalApplicationCommandAsync(builder.Build());
SlashCommands.Add(instance);
Config.Logger.Log($"[SLASH] Instance: {type.FullName} loaded !", source: typeof(PluginLoader));
}
}
catch (Exception ex)
{
//Console.WriteLine(ex.Message);
Config.Logger.Log(ex.Message, source: typeof(PluginLoader), type: LogType.ERROR);
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
using Discord;
using PluginManager.Interfaces;
using PluginManager.Others;
namespace PluginManager.Loaders;
internal static class PluginLoaderExtensions
{
internal static bool TryStartEvent(this PluginLoader pluginLoader, DBEvent? dbEvent)
{
try
{
if (dbEvent is null)
{
throw new ArgumentNullException(nameof(dbEvent));
}
dbEvent.Start(pluginLoader._Client);
return true;
}
catch (Exception e)
{
Config.Logger.Log($"Error starting event {dbEvent.Name}: {e.Message}", typeof(PluginLoader), LogType.ERROR);
return false;
}
}
internal static bool TryStartSlashCommand(this PluginLoader pluginLoader, DBSlashCommand? dbSlashCommand)
{
try
{
if (dbSlashCommand is null)
{
throw new ArgumentNullException(nameof(dbSlashCommand));
}
var builder = new SlashCommandBuilder();
builder.WithName(dbSlashCommand.Name);
builder.WithDescription(dbSlashCommand.Description);
builder.WithDMPermission(dbSlashCommand.canUseDM);
builder.Options = dbSlashCommand.Options;
pluginLoader._Client.CreateGlobalApplicationCommandAsync(builder.Build());
return true;
}
catch (Exception e)
{
Config.Logger.Log($"Error starting slash command {dbSlashCommand.Name}: {e.Message}", typeof(PluginLoader), LogType.ERROR);
return false;
}
}
}