From f68b6cb877890b423609448476e26cf31fc22919 Mon Sep 17 00:00:00 2001 From: Andrei Tudor Date: Tue, 17 Jun 2025 17:20:03 +0300 Subject: [PATCH] Fixed plugin reloading --- .../IPluginLoader.cs | 2 +- .../PluginLoader.cs | 96 ++++++++++++------- DiscordBotCore/Bot/DiscordBotApplication.cs | 7 +- SethDiscordBot.sln | 15 --- WebUI/Components/Pages/Plugins/Local.razor | 2 +- WebUI/Components/Pages/Settings.razor | 2 +- 6 files changed, 68 insertions(+), 56 deletions(-) diff --git a/DiscordBotCore.PluginManagement.Loading/IPluginLoader.cs b/DiscordBotCore.PluginManagement.Loading/IPluginLoader.cs index b02f3bb..87583f0 100644 --- a/DiscordBotCore.PluginManagement.Loading/IPluginLoader.cs +++ b/DiscordBotCore.PluginManagement.Loading/IPluginLoader.cs @@ -23,5 +23,5 @@ public interface IPluginLoader /// /// Unload all plugins from the plugin manager. /// - public void UnloadAllPlugins(); + public Task UnloadAllPlugins(); } \ No newline at end of file diff --git a/DiscordBotCore.PluginManagement.Loading/PluginLoader.cs b/DiscordBotCore.PluginManagement.Loading/PluginLoader.cs index 9615fbd..dea8f4c 100644 --- a/DiscordBotCore.PluginManagement.Loading/PluginLoader.cs +++ b/DiscordBotCore.PluginManagement.Loading/PluginLoader.cs @@ -7,6 +7,7 @@ using DiscordBotCore.Logging; using DiscordBotCore.PluginCore.Helpers.Execution.DbEvent; using DiscordBotCore.PluginCore.Interfaces; using DiscordBotCore.PluginManagement.Loading.Exceptions; +using DiscordBotCore.Utilities.Responses; namespace DiscordBotCore.PluginManagement.Loading; @@ -24,8 +25,7 @@ public class PluginLoader : IPluginLoader private readonly List _Commands = new List(); private readonly List _Events = new List(); private readonly List _SlashCommands = new List(); - - private bool _IsFirstLoad = true; + private readonly List _ApplicationCommands = new List(); public PluginLoader(IPluginManager pluginManager, ILogger logger, IConfiguration configuration) { @@ -57,11 +57,16 @@ public class PluginLoader : IPluginLoader public async Task LoadPlugins() { - UnloadAllPlugins(); + if (PluginLoaderContext is not null) + { + _Logger.Log("The plugins are already loaded", this, LogType.Error); + return; + } _Events.Clear(); _Commands.Clear(); _SlashCommands.Clear(); + _ApplicationCommands.Clear(); await LoadPluginFiles(); @@ -88,37 +93,45 @@ public class PluginLoader : IPluginLoader _Logger.Log("Loaded plugins", this); } - public void UnloadAllPlugins() + public async Task UnloadAllPlugins() { - if (_IsFirstLoad) - { - // Allow unloading only after the first load - _IsFirstLoad = false; - return; - } - if (PluginLoaderContext is null) { _Logger.Log("The plugins are not loaded. Please load the plugins before unloading them.", this, LogType.Error); return; } + await UnloadSlashCommands(); + PluginLoaderContext.Unload(); + PluginLoaderContext = null; + GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); - PluginLoaderContext = null; + + } + + private async Task UnloadSlashCommands() + { + if (_DiscordClient is null) + { + _Logger.Log("The client is not set. Please set the client before unloading slash commands.", this, LogType.Error); + return; + } + + foreach (SocketApplicationCommand command in _ApplicationCommands) + { + await command.DeleteAsync(); + } + + _ApplicationCommands.Clear(); + _Logger.Log("Unloaded all slash commands", this); } private async Task LoadPluginFiles() { - if (PluginLoaderContext is not null) - { - _Logger.Log("The plugins are already loaded", this, LogType.Error); - return; - } - var installedPlugins = await _PluginManager.GetInstalledPlugins(); if (installedPlugins.Count == 0) @@ -314,34 +327,45 @@ public class PluginLoader : IPluginLoader builder.WithContextTypes(InteractionContextType.Guild); List serverIds = _Configuration.GetList("ServerIds", new List()); - - foreach(ulong guildId in serverIds) - { - bool result = await EnableSlashCommandPerGuild(guildId, builder); - - if (!result) - { - _Logger.Log($"Failed to enable slash command {dbSlashCommand.Name} for guild {guildId}", this, LogType.Error); - return false; - } - } - - await _DiscordClient.CreateGlobalApplicationCommandAsync(builder.Build()); + if (serverIds.Any()) + { + foreach(ulong guildId in serverIds) + { + IResponse result = await EnableSlashCommandPerGuild(guildId, builder); + + if (!result.IsSuccess) + { + _Logger.Log($"Failed to enable slash command {dbSlashCommand.Name} for guild {guildId}", this, LogType.Error); + continue; + } + + if (result.Data is null) + { + continue; + } + + _ApplicationCommands.Add(result.Data); + } + + return true; + } + + var command = await _DiscordClient.CreateGlobalApplicationCommandAsync(builder.Build()); + _ApplicationCommands.Add(command); return true; } - private async Task EnableSlashCommandPerGuild(ulong guildId, SlashCommandBuilder builder) + private async Task> EnableSlashCommandPerGuild(ulong guildId, SlashCommandBuilder builder) { SocketGuild? guild = _DiscordClient?.GetGuild(guildId); if (guild is null) { _Logger.Log("Failed to get guild with ID " + guildId, this, LogType.Error); - return false; + return Response.Failure("Failed to get guild with ID " + guildId); } - await guild.CreateApplicationCommandAsync(builder.Build()); - - return true; + var command = await guild.CreateApplicationCommandAsync(builder.Build()); + return Response.Success(command); } } \ No newline at end of file diff --git a/DiscordBotCore/Bot/DiscordBotApplication.cs b/DiscordBotCore/Bot/DiscordBotApplication.cs index d7edd8d..683bee9 100644 --- a/DiscordBotCore/Bot/DiscordBotApplication.cs +++ b/DiscordBotCore/Bot/DiscordBotApplication.cs @@ -44,6 +44,8 @@ public class DiscordBotApplication : IDiscordBotApplication return; } + await _PluginLoader.UnloadAllPlugins(); + await Client.LogoutAsync(); await Client.StopAsync(); @@ -54,6 +56,7 @@ public class DiscordBotApplication : IDiscordBotApplication await Client.DisposeAsync(); + IsReady = false; } @@ -73,7 +76,7 @@ public class DiscordBotApplication : IDiscordBotApplication }; DiscordSocketClient client = new DiscordSocketClient(config); - Client = client; + _Service = new CommandService(); @@ -82,8 +85,8 @@ public class DiscordBotApplication : IDiscordBotApplication client.Ready += Ready; client.Disconnected += Client_Disconnected; + Client = client; await client.LoginAsync(TokenType.Bot, _Configuration.Get("token")); - await client.StartAsync(); _CommandServiceHandler = new CommandHandler(_Logger, _PluginLoader, _Configuration, _Service); diff --git a/SethDiscordBot.sln b/SethDiscordBot.sln index ceff943..357ccbc 100644 --- a/SethDiscordBot.sln +++ b/SethDiscordBot.sln @@ -13,8 +13,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{EA4F EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LevelingSystem", "Plugins\LevelingSystem\LevelingSystem.csproj", "{FCE9743F-7EB4-4639-A080-FCDDFCC7D689}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MusicPlayer", "Plugins\MusicPlayer\MusicPlayer.csproj", "{F3C61A47-F758-4145-B496-E3ECCF979D89}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CppCompatibilityModule", "Modules\CppCompatibilityModule\CppCompatibilityModule.csproj", "{C67908F9-4A55-4DD8-B993-C26C648226F1}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscordBotCore.PluginCore", "DiscordBotCore.PluginCore\DiscordBotCore.PluginCore.csproj", "{B5725C86-2633-4C7A-A6A4-49AAA2767E54}" @@ -77,18 +75,6 @@ Global {FCE9743F-7EB4-4639-A080-FCDDFCC7D689}.Release|ARM64.Build.0 = Release|ARM64 {FCE9743F-7EB4-4639-A080-FCDDFCC7D689}.Release|x64.ActiveCfg = Release|x64 {FCE9743F-7EB4-4639-A080-FCDDFCC7D689}.Release|x64.Build.0 = Release|x64 - {F3C61A47-F758-4145-B496-E3ECCF979D89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F3C61A47-F758-4145-B496-E3ECCF979D89}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F3C61A47-F758-4145-B496-E3ECCF979D89}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {F3C61A47-F758-4145-B496-E3ECCF979D89}.Debug|ARM64.Build.0 = Debug|ARM64 - {F3C61A47-F758-4145-B496-E3ECCF979D89}.Debug|x64.ActiveCfg = Debug|x64 - {F3C61A47-F758-4145-B496-E3ECCF979D89}.Debug|x64.Build.0 = Debug|x64 - {F3C61A47-F758-4145-B496-E3ECCF979D89}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F3C61A47-F758-4145-B496-E3ECCF979D89}.Release|Any CPU.Build.0 = Release|Any CPU - {F3C61A47-F758-4145-B496-E3ECCF979D89}.Release|ARM64.ActiveCfg = Release|ARM64 - {F3C61A47-F758-4145-B496-E3ECCF979D89}.Release|ARM64.Build.0 = Release|ARM64 - {F3C61A47-F758-4145-B496-E3ECCF979D89}.Release|x64.ActiveCfg = Release|x64 - {F3C61A47-F758-4145-B496-E3ECCF979D89}.Release|x64.Build.0 = Release|x64 {C67908F9-4A55-4DD8-B993-C26C648226F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C67908F9-4A55-4DD8-B993-C26C648226F1}.Debug|Any CPU.Build.0 = Debug|Any CPU {C67908F9-4A55-4DD8-B993-C26C648226F1}.Debug|ARM64.ActiveCfg = Debug|ARM64 @@ -251,7 +237,6 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {FCE9743F-7EB4-4639-A080-FCDDFCC7D689} = {5CF9AD7B-6BF0-4035-835F-722F989C01E1} - {F3C61A47-F758-4145-B496-E3ECCF979D89} = {5CF9AD7B-6BF0-4035-835F-722F989C01E1} {C67908F9-4A55-4DD8-B993-C26C648226F1} = {EA4FA308-7B2C-458E-8485-8747D745DD59} {9A4B98C1-00AC-481C-BE55-A70C0B9D3BE7} = {5CF9AD7B-6BF0-4035-835F-722F989C01E1} {94238D37-60C6-4E40-80EC-4B4D242F5914} = {8F27B3EA-F292-40DF-B9B3-4B0E6BEA4E70} diff --git a/WebUI/Components/Pages/Plugins/Local.razor b/WebUI/Components/Pages/Plugins/Local.razor index 10e7b28..d6a2657 100644 --- a/WebUI/Components/Pages/Plugins/Local.razor +++ b/WebUI/Components/Pages/Plugins/Local.razor @@ -82,7 +82,7 @@ private async Task DeletePluginButtonClick(InstalledPlugin plugin) { - PluginLoader.UnloadAllPlugins(); + await PluginLoader.UnloadAllPlugins(); Logger.Log($"Deleting plugin {plugin.Name}", this); diff --git a/WebUI/Components/Pages/Settings.razor b/WebUI/Components/Pages/Settings.razor index ed83135..d1eb67e 100644 --- a/WebUI/Components/Pages/Settings.razor +++ b/WebUI/Components/Pages/Settings.razor @@ -30,7 +30,7 @@