From f1dc717049a8bde4085c3cba7288335a8a1ab14d Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sat, 12 Apr 2025 13:42:39 +0200 Subject: [PATCH] Fixed the plugin factory setup; it runs after the data directory is known --- .../Layout/MainLayout.razor.cs | 55 ++++++++++++------- app/MindWork AI Studio/Tools/Event.cs | 1 + .../PluginSystem/PluginFactory.HotReload.cs | 6 ++ .../PluginSystem/PluginFactory.Internal.cs | 6 ++ .../Tools/PluginSystem/PluginFactory.cs | 38 +++++++++---- 5 files changed, 73 insertions(+), 33 deletions(-) diff --git a/app/MindWork AI Studio/Layout/MainLayout.razor.cs b/app/MindWork AI Studio/Layout/MainLayout.razor.cs index 2586d185..b80de4a5 100644 --- a/app/MindWork AI Studio/Layout/MainLayout.razor.cs +++ b/app/MindWork AI Studio/Layout/MainLayout.razor.cs @@ -83,29 +83,13 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis // Ensure that all settings are loaded: await this.SettingsManager.LoadSettings(); - // - // We cannot process the plugins before the settings are loaded, - // and we know our data directory. - // - if(PreviewFeatures.PRE_PLUGINS_2025.IsEnabled(this.SettingsManager)) - { - _ = Task.Run(async () => - { - // Ensure that all internal plugins are present: - await PluginFactory.EnsureInternalPlugins(); - - // Load (but not start) all plugins, without waiting for them: - var pluginLoadingTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)); - await PluginFactory.LoadAll(pluginLoadingTimeout.Token); - - // Set up hot reloading for plugins: - PluginFactory.SetUpHotReloading(); - }); - } - // Register this component with the message bus: this.MessageBus.RegisterComponent(this); - this.MessageBus.ApplyFilters(this, [], [ Event.UPDATE_AVAILABLE, Event.CONFIGURATION_CHANGED, Event.COLOR_THEME_CHANGED, Event.SHOW_ERROR ]); + this.MessageBus.ApplyFilters(this, [], + [ + Event.UPDATE_AVAILABLE, Event.CONFIGURATION_CHANGED, Event.COLOR_THEME_CHANGED, Event.SHOW_ERROR, + Event.STARTUP_PLUGIN_SYSTEM, Event.PLUGINS_RELOADED + ]); // Set the snackbar for the update service: UpdateService.SetBlazorDependencies(this.Snackbar); @@ -118,6 +102,9 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis // Solve issue https://github.com/MudBlazor/MudBlazor/issues/11133: MudGlobal.TooltipDefaults.Duration = TimeSpan.Zero; + // Send a message to start the plugin system: + await this.MessageBus.SendMessage(this, Event.STARTUP_PLUGIN_SYSTEM); + await this.themeProvider.WatchSystemPreference(this.SystemeThemeChanged); await this.UpdateThemeConfiguration(); this.LoadNavItems(); @@ -182,6 +169,32 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis error.Show(this.Snackbar); break; + + case Event.STARTUP_PLUGIN_SYSTEM: + if(PreviewFeatures.PRE_PLUGINS_2025.IsEnabled(this.SettingsManager)) + { + _ = Task.Run(async () => + { + // Set up the plugin system: + PluginFactory.Setup(); + + // Ensure that all internal plugins are present: + await PluginFactory.EnsureInternalPlugins(); + + // Load (but not start) all plugins, without waiting for them: + var pluginLoadingTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(5)); + await PluginFactory.LoadAll(pluginLoadingTimeout.Token); + + // Set up hot reloading for plugins: + PluginFactory.SetUpHotReloading(); + }); + } + + break; + + case Event.PLUGINS_RELOADED: + await this.InvokeAsync(this.StateHasChanged); + break; } } diff --git a/app/MindWork AI Studio/Tools/Event.cs b/app/MindWork AI Studio/Tools/Event.cs index 57758589..213adf29 100644 --- a/app/MindWork AI Studio/Tools/Event.cs +++ b/app/MindWork AI Studio/Tools/Event.cs @@ -8,6 +8,7 @@ public enum Event STATE_HAS_CHANGED, CONFIGURATION_CHANGED, COLOR_THEME_CHANGED, + STARTUP_PLUGIN_SYSTEM, PLUGINS_RELOADED, SHOW_ERROR, diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.HotReload.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.HotReload.cs index c2d75bf3..0a32c17d 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.HotReload.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.HotReload.cs @@ -4,6 +4,12 @@ public static partial class PluginFactory { public static void SetUpHotReloading() { + if (!IS_INITIALIZED) + { + LOG.LogError("PluginFactory is not initialized. Please call Setup() before using it."); + return; + } + LOG.LogInformation($"Start hot reloading plugins for path '{HOT_RELOAD_WATCHER.Path}'."); try { diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Internal.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Internal.cs index cda389cf..0a9e9dac 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Internal.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Internal.cs @@ -10,6 +10,12 @@ public static partial class PluginFactory { public static async Task EnsureInternalPlugins() { + if (!IS_INITIALIZED) + { + LOG.LogError("PluginFactory is not initialized. Please call Setup() before using it."); + return; + } + LOG.LogInformation("Start ensuring internal plugins."); foreach (var plugin in Enum.GetValues()) { diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.cs index 18d2023b..496000b8 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.cs @@ -9,29 +9,34 @@ namespace AIStudio.Tools.PluginSystem; public static partial class PluginFactory { - private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger("PluginFactory"); - - private static readonly string DATA_DIR = SettingsManager.DataDirectory!; - - private static readonly string PLUGINS_ROOT = Path.Join(DATA_DIR, "plugins"); - - private static readonly string INTERNAL_PLUGINS_ROOT = Path.Join(PLUGINS_ROOT, ".internal"); + private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger(nameof(PluginFactory)); + private static readonly List AVAILABLE_PLUGINS = []; - private static readonly FileSystemWatcher HOT_RELOAD_WATCHER; - - private static readonly List AVAILABLE_PLUGINS = []; + private static bool IS_INITIALIZED; + private static string DATA_DIR = string.Empty; + private static string PLUGINS_ROOT = string.Empty; + private static string INTERNAL_PLUGINS_ROOT = string.Empty; + private static FileSystemWatcher HOT_RELOAD_WATCHER = null!; /// /// A list of all available plugins. /// public static IReadOnlyCollection AvailablePlugins => AVAILABLE_PLUGINS; - - static PluginFactory() + /// + /// Set up the plugin factory. We will read the data directory from the settings manager. + /// Afterward, we will create the plugins directory and the internal plugin directory. + /// + public static void Setup() { + DATA_DIR = SettingsManager.DataDirectory!; + PLUGINS_ROOT = Path.Join(DATA_DIR, "plugins"); + INTERNAL_PLUGINS_ROOT = Path.Join(PLUGINS_ROOT, ".internal"); + if (!Directory.Exists(PLUGINS_ROOT)) Directory.CreateDirectory(PLUGINS_ROOT); HOT_RELOAD_WATCHER = new(PLUGINS_ROOT); + IS_INITIALIZED = true; } /// @@ -48,6 +53,12 @@ public static partial class PluginFactory /// public static async Task LoadAll(CancellationToken cancellationToken = default) { + if (!IS_INITIALIZED) + { + LOG.LogError("PluginFactory is not initialized. Please call Setup() before using it."); + return; + } + LOG.LogInformation("Start loading plugins."); if (!Directory.Exists(PLUGINS_ROOT)) { @@ -151,6 +162,9 @@ public static partial class PluginFactory public static void Dispose() { + if(!IS_INITIALIZED) + return; + HOT_RELOAD_WATCHER.Dispose(); } } \ No newline at end of file