Updated performance in plugin loading
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using DiscordBotCore.Interfaces;
|
||||
using DiscordBotCore.Others;
|
||||
using DiscordBotCore.Others.Exceptions;
|
||||
|
||||
namespace DiscordBotCore.Loaders;
|
||||
|
||||
@@ -13,7 +12,7 @@ internal class Loader
|
||||
|
||||
internal delegate void FileLoadedHandler(FileLoaderResult result);
|
||||
|
||||
internal delegate void PluginLoadedHandler(PluginLoadResultData result);
|
||||
internal delegate void PluginLoadedHandler(PluginLoaderResult result);
|
||||
|
||||
internal event FileLoadedHandler? OnFileLoadedException;
|
||||
internal event PluginLoadedHandler? OnPluginLoaded;
|
||||
@@ -21,8 +20,8 @@ internal class Loader
|
||||
internal async Task Load()
|
||||
{
|
||||
var installedPlugins = await Application.CurrentApplication.PluginManager.GetInstalledPlugins();
|
||||
var files = installedPlugins.Where(plugin=>plugin.IsEnabled).Select(plugin => plugin.FilePath).ToArray();
|
||||
|
||||
var files = installedPlugins.Where(plugin => plugin.IsEnabled).Select(plugin => plugin.FilePath).ToArray();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
try
|
||||
@@ -41,7 +40,7 @@ internal class Loader
|
||||
await LoadEverythingOfType<ICommandAction>();
|
||||
}
|
||||
|
||||
private async Task LoadEverythingOfType<T>()
|
||||
private Task LoadEverythingOfType<T>()
|
||||
{
|
||||
var types = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(s => s.GetTypes())
|
||||
@@ -58,25 +57,24 @@ internal class Loader
|
||||
throw new Exception($"Failed to create instance of plugin with type {type.FullName} [{type.Assembly}]");
|
||||
}
|
||||
|
||||
var pluginType = plugin switch
|
||||
PluginLoaderResult result = plugin switch
|
||||
{
|
||||
IDbEvent => PluginType.EVENT,
|
||||
IDbCommand => PluginType.COMMAND,
|
||||
IDbSlashCommand => PluginType.SLASH_COMMAND,
|
||||
ICommandAction => PluginType.ACTION,
|
||||
_ => PluginType.UNKNOWN
|
||||
IDbEvent @event => PluginLoaderResult.FromIDbEvent(@event),
|
||||
IDbCommand command => PluginLoaderResult.FromIDbCommand(command),
|
||||
IDbSlashCommand command => PluginLoaderResult.FromIDbSlashCommand(command),
|
||||
ICommandAction action => PluginLoaderResult.FromICommandAction(action),
|
||||
_ => PluginLoaderResult.FromException(new PluginNotFoundException($"Unknown plugin type {plugin.GetType().FullName}"))
|
||||
};
|
||||
|
||||
if (pluginType == PluginType.UNKNOWN)
|
||||
throw new Exception($"Unknown plugin type for plugin with type {type.FullName} [{type.Assembly}]");
|
||||
|
||||
OnPluginLoaded?.Invoke(new PluginLoadResultData(type.FullName, pluginType, true, plugin: plugin));
|
||||
OnPluginLoaded?.Invoke(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnPluginLoaded?.Invoke(new PluginLoadResultData(type.FullName, PluginType.UNKNOWN, false, ex.Message));
|
||||
OnPluginLoaded?.Invoke(PluginLoaderResult.FromException(ex));
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
using DiscordBotCore.Others;
|
||||
|
||||
namespace DiscordBotCore.Loaders;
|
||||
|
||||
public class PluginLoadResultData
|
||||
{
|
||||
public string PluginName { get; init; }
|
||||
public PluginType PluginType { get; init; }
|
||||
public string? ErrorMessage { get; init; }
|
||||
public bool IsSuccess { get; init; }
|
||||
|
||||
public object Plugin { get; init; }
|
||||
|
||||
public PluginLoadResultData(string pluginName, PluginType pluginType, bool isSuccess, string? errorMessage = null,
|
||||
object? plugin = null)
|
||||
{
|
||||
PluginName = pluginName;
|
||||
PluginType = pluginType;
|
||||
IsSuccess = isSuccess;
|
||||
ErrorMessage = errorMessage;
|
||||
Plugin = plugin is null ? new() : plugin;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using DiscordBotCore.Interfaces;
|
||||
using DiscordBotCore.Others;
|
||||
using DiscordBotCore.Others.Exceptions;
|
||||
|
||||
|
||||
namespace DiscordBotCore.Loaders;
|
||||
|
||||
public class PluginLoader
|
||||
public sealed class PluginLoader
|
||||
{
|
||||
internal readonly DiscordSocketClient _Client;
|
||||
|
||||
public delegate void CommandLoaded(PluginLoadResultData resultData);
|
||||
|
||||
public delegate void EventLoaded(PluginLoadResultData resultData);
|
||||
|
||||
public delegate void SlashCommandLoaded(PluginLoadResultData resultData);
|
||||
|
||||
public delegate void ActionLoaded(PluginLoadResultData resultData);
|
||||
private readonly DiscordSocketClient _Client;
|
||||
public delegate void CommandLoaded(IDbCommand eCommand);
|
||||
public delegate void EventLoaded(IDbEvent eEvent);
|
||||
public delegate void SlashCommandLoaded(IDbSlashCommand eSlashCommand);
|
||||
public delegate void ActionLoaded(ICommandAction eAction);
|
||||
|
||||
public CommandLoaded? OnCommandLoaded;
|
||||
public EventLoaded? OnEventLoaded;
|
||||
@@ -38,13 +34,6 @@ public class PluginLoader
|
||||
|
||||
public async Task LoadPlugins()
|
||||
{
|
||||
|
||||
if (_Client == null)
|
||||
{
|
||||
Application.Logger.Log("Discord client is null", this, LogType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
Commands.Clear();
|
||||
Events.Clear();
|
||||
SlashCommands.Clear();
|
||||
@@ -65,48 +54,62 @@ public class PluginLoader
|
||||
Application.Logger.Log(result.ErrorMessage, this, LogType.Error);
|
||||
}
|
||||
|
||||
private async void OnPluginLoaded(PluginLoadResultData result)
|
||||
private async void InitializeCommand(ICommandAction action)
|
||||
{
|
||||
switch (result.PluginType)
|
||||
if (action.RunType == InternalActionRunType.OnStartup || action.RunType == InternalActionRunType.OnStartupAndCall)
|
||||
await Application.CurrentApplication.InternalActionManager.StartAction(action, null);
|
||||
|
||||
if(action.RunType == InternalActionRunType.OnCall || action.RunType == InternalActionRunType.OnStartupAndCall)
|
||||
Actions.Add(action);
|
||||
|
||||
OnActionLoaded?.Invoke(action);
|
||||
}
|
||||
|
||||
private void InitializeDbCommand(IDbCommand command)
|
||||
{
|
||||
Commands.Add(command);
|
||||
OnCommandLoaded?.Invoke(command);
|
||||
}
|
||||
|
||||
private void InitializeEvent(IDbEvent eEvent)
|
||||
{
|
||||
if (!eEvent.TryStartEvent())
|
||||
{
|
||||
case PluginType.ACTION:
|
||||
ICommandAction action = (ICommandAction)result.Plugin;
|
||||
if (action.RunType == InternalActionRunType.OnStartup || action.RunType == InternalActionRunType.OnStartupAndCall)
|
||||
await Application.CurrentApplication.InternalActionManager.StartAction(action, null);
|
||||
|
||||
if(action.RunType == InternalActionRunType.OnCall || action.RunType == InternalActionRunType.OnStartupAndCall)
|
||||
Actions.Add(action);
|
||||
|
||||
OnActionLoaded?.Invoke(result);
|
||||
|
||||
break;
|
||||
case PluginType.COMMAND:
|
||||
Commands.Add((IDbCommand)result.Plugin);
|
||||
OnCommandLoaded?.Invoke(result);
|
||||
break;
|
||||
case PluginType.EVENT:
|
||||
if (this.TryStartEvent((IDbEvent)result.Plugin))
|
||||
{
|
||||
Events.Add((IDbEvent)result.Plugin);
|
||||
OnEventLoaded?.Invoke(result);
|
||||
}
|
||||
|
||||
break;
|
||||
case PluginType.SLASH_COMMAND:
|
||||
if (await this.TryStartSlashCommand((IDbSlashCommand)result.Plugin))
|
||||
{
|
||||
if(((IDbSlashCommand)result.Plugin).HasInteraction)
|
||||
_Client.InteractionCreated += ((IDbSlashCommand)result.Plugin).ExecuteInteraction;
|
||||
SlashCommands.Add((IDbSlashCommand)result.Plugin);
|
||||
OnSlashCommandLoaded?.Invoke(result);
|
||||
}
|
||||
else
|
||||
Application.Logger.Log($"Failed to start slash command {result.PluginName}", this, LogType.Error);
|
||||
break;
|
||||
case PluginType.UNKNOWN:
|
||||
default:
|
||||
Application.Logger.Log("Unknown plugin type", this, LogType.Error);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
Events.Add(eEvent);
|
||||
OnEventLoaded?.Invoke(eEvent);
|
||||
}
|
||||
|
||||
private async void InitializeSlashCommand(IDbSlashCommand slashCommand)
|
||||
{
|
||||
Result result = await slashCommand.TryStartSlashCommand();
|
||||
result.Match(
|
||||
() =>
|
||||
{
|
||||
if (slashCommand.HasInteraction)
|
||||
_Client.InteractionCreated += slashCommand.ExecuteInteraction;
|
||||
SlashCommands.Add(slashCommand);
|
||||
OnSlashCommandLoaded?.Invoke(slashCommand);
|
||||
},
|
||||
HandleError
|
||||
);
|
||||
}
|
||||
|
||||
private void HandleError(Exception exception)
|
||||
{
|
||||
Application.Logger.Log(exception.Message, this, LogType.Error);
|
||||
}
|
||||
|
||||
private void OnPluginLoaded(PluginLoaderResult result)
|
||||
{
|
||||
result.Match(
|
||||
InitializeDbCommand,
|
||||
InitializeEvent,
|
||||
InitializeSlashCommand,
|
||||
InitializeCommand,
|
||||
HandleError
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace DiscordBotCore.Loaders;
|
||||
|
||||
internal static class PluginLoaderExtensions
|
||||
{
|
||||
internal static bool TryStartEvent(this PluginLoader pluginLoader, IDbEvent? dbEvent)
|
||||
internal static bool TryStartEvent(this IDbEvent? dbEvent)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -23,7 +23,7 @@ internal static class PluginLoaderExtensions
|
||||
throw new ArgumentNullException(nameof(dbEvent));
|
||||
}
|
||||
|
||||
dbEvent.Start(pluginLoader._Client);
|
||||
dbEvent.Start(Application.CurrentApplication.DiscordBotClient.Client);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -34,18 +34,18 @@ internal static class PluginLoaderExtensions
|
||||
}
|
||||
}
|
||||
|
||||
internal static async Task<bool> TryStartSlashCommand(this PluginLoader pluginLoader, IDbSlashCommand? dbSlashCommand)
|
||||
internal static async Task<Result> TryStartSlashCommand(this IDbSlashCommand? dbSlashCommand)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (dbSlashCommand is null)
|
||||
{
|
||||
return false;
|
||||
return Result.Failure(new Exception("dbSlashCommand is null"));
|
||||
}
|
||||
|
||||
if (pluginLoader._Client.Guilds.Count == 0)
|
||||
if (Application.CurrentApplication.DiscordBotClient.Client.Guilds.Count == 0)
|
||||
{
|
||||
return false;
|
||||
return Result.Failure(new Exception("No guilds found"));
|
||||
}
|
||||
|
||||
var builder = new SlashCommandBuilder();
|
||||
@@ -60,28 +60,27 @@ internal static class PluginLoaderExtensions
|
||||
|
||||
foreach(ulong guildId in Application.CurrentApplication.ServerIDs)
|
||||
{
|
||||
bool result = await pluginLoader.EnableSlashCommandPerGuild(guildId, builder);
|
||||
bool result = await EnableSlashCommandPerGuild(guildId, builder);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
Application.Logger.Log($"Failed to enable slash command {dbSlashCommand.Name} for guild {guildId}", typeof(PluginLoader), LogType.Error);
|
||||
return Result.Failure($"Failed to enable slash command {dbSlashCommand.Name} for guild {guildId}");
|
||||
}
|
||||
}
|
||||
|
||||
await pluginLoader._Client.CreateGlobalApplicationCommandAsync(builder.Build());
|
||||
await Application.CurrentApplication.DiscordBotClient.Client.CreateGlobalApplicationCommandAsync(builder.Build());
|
||||
|
||||
return true;
|
||||
return Result.Success();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Application.Logger.Log($"Error starting slash command {dbSlashCommand.Name}: {e.Message}", typeof(PluginLoader), LogType.Error);
|
||||
return false;
|
||||
return Result.Failure("Error starting slash command");
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<bool> EnableSlashCommandPerGuild(this PluginLoader pluginLoader, ulong guildId, SlashCommandBuilder builder)
|
||||
private static async Task<bool> EnableSlashCommandPerGuild(ulong guildId, SlashCommandBuilder builder)
|
||||
{
|
||||
SocketGuild? guild = pluginLoader._Client.GetGuild(guildId);
|
||||
SocketGuild? guild = Application.CurrentApplication.DiscordBotClient.Client.GetGuild(guildId);
|
||||
if (guild is null)
|
||||
{
|
||||
Application.Logger.Log("Failed to get guild with ID " + guildId, typeof(PluginLoader), LogType.Error);
|
||||
|
||||
42
DiscordBotCore/Loaders/PluginLoaderResult.cs
Normal file
42
DiscordBotCore/Loaders/PluginLoaderResult.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using DiscordBotCore.Interfaces;
|
||||
using DiscordBotCore.Others;
|
||||
using DiscordBotCore.Others.Exceptions;
|
||||
|
||||
namespace DiscordBotCore.Loaders;
|
||||
|
||||
|
||||
public class PluginLoaderResult
|
||||
{
|
||||
private Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception> _Result;
|
||||
|
||||
public static PluginLoaderResult FromIDbCommand(IDbCommand command) => new PluginLoaderResult(new Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception>(command));
|
||||
|
||||
public static PluginLoaderResult FromIDbEvent(IDbEvent dbEvent) => new PluginLoaderResult(new Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception>(dbEvent));
|
||||
|
||||
public static PluginLoaderResult FromIDbSlashCommand(IDbSlashCommand slashCommand) => new PluginLoaderResult(new Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception>(slashCommand));
|
||||
|
||||
public static PluginLoaderResult FromICommandAction(ICommandAction commandAction) => new PluginLoaderResult(new Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception>(commandAction));
|
||||
|
||||
public static PluginLoaderResult FromException(Exception exception) => new PluginLoaderResult(new Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception>(exception));
|
||||
public static PluginLoaderResult FromException(string exception) => new PluginLoaderResult(new Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception>(new Exception(message: exception)));
|
||||
|
||||
private PluginLoaderResult(Option4<IDbCommand, IDbEvent, IDbSlashCommand, ICommandAction, Exception> result)
|
||||
{
|
||||
_Result = result;
|
||||
}
|
||||
|
||||
public void Match(Action<IDbCommand> commandAction, Action<IDbEvent> eventAction, Action<IDbSlashCommand> slashCommandAction,
|
||||
Action<ICommandAction> commandActionAction, Action<Exception> exceptionAction)
|
||||
{
|
||||
_Result.Match(commandAction, eventAction, slashCommandAction, commandActionAction, exceptionAction);
|
||||
}
|
||||
|
||||
public TResult Match<TResult>(Func<IDbCommand, TResult> commandFunc, Func<IDbEvent, TResult> eventFunc,
|
||||
Func<IDbSlashCommand, TResult> slashCommandFunc, Func<ICommandAction, TResult> commandActionFunc,
|
||||
Func<Exception, TResult> exceptionFunc)
|
||||
{
|
||||
return _Result.Match(commandFunc, eventFunc, slashCommandFunc, commandActionFunc, exceptionFunc);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user