Fixed the plugin factory setup; it runs after the data directory is known

This commit is contained in:
Thorsten Sommer 2025-04-12 13:42:39 +02:00
parent 42845eab90
commit f1dc717049
Signed by: tsommer
GPG Key ID: 371BBA77A02C0108
5 changed files with 73 additions and 33 deletions

View File

@ -83,29 +83,13 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis
// Ensure that all settings are loaded: // Ensure that all settings are loaded:
await this.SettingsManager.LoadSettings(); 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: // Register this component with the message bus:
this.MessageBus.RegisterComponent(this); 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: // Set the snackbar for the update service:
UpdateService.SetBlazorDependencies(this.Snackbar); UpdateService.SetBlazorDependencies(this.Snackbar);
@ -118,6 +102,9 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis
// Solve issue https://github.com/MudBlazor/MudBlazor/issues/11133: // Solve issue https://github.com/MudBlazor/MudBlazor/issues/11133:
MudGlobal.TooltipDefaults.Duration = TimeSpan.Zero; MudGlobal.TooltipDefaults.Duration = TimeSpan.Zero;
// Send a message to start the plugin system:
await this.MessageBus.SendMessage<bool>(this, Event.STARTUP_PLUGIN_SYSTEM);
await this.themeProvider.WatchSystemPreference(this.SystemeThemeChanged); await this.themeProvider.WatchSystemPreference(this.SystemeThemeChanged);
await this.UpdateThemeConfiguration(); await this.UpdateThemeConfiguration();
this.LoadNavItems(); this.LoadNavItems();
@ -182,6 +169,32 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis
error.Show(this.Snackbar); error.Show(this.Snackbar);
break; 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;
} }
} }

View File

@ -8,6 +8,7 @@ public enum Event
STATE_HAS_CHANGED, STATE_HAS_CHANGED,
CONFIGURATION_CHANGED, CONFIGURATION_CHANGED,
COLOR_THEME_CHANGED, COLOR_THEME_CHANGED,
STARTUP_PLUGIN_SYSTEM,
PLUGINS_RELOADED, PLUGINS_RELOADED,
SHOW_ERROR, SHOW_ERROR,

View File

@ -4,6 +4,12 @@ public static partial class PluginFactory
{ {
public static void SetUpHotReloading() 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}'."); LOG.LogInformation($"Start hot reloading plugins for path '{HOT_RELOAD_WATCHER.Path}'.");
try try
{ {

View File

@ -10,6 +10,12 @@ public static partial class PluginFactory
{ {
public static async Task EnsureInternalPlugins() 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."); LOG.LogInformation("Start ensuring internal plugins.");
foreach (var plugin in Enum.GetValues<InternalPlugin>()) foreach (var plugin in Enum.GetValues<InternalPlugin>())
{ {

View File

@ -9,29 +9,34 @@ namespace AIStudio.Tools.PluginSystem;
public static partial class PluginFactory public static partial class PluginFactory
{ {
private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger("PluginFactory"); private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger(nameof(PluginFactory));
private static readonly List<IAvailablePlugin> AVAILABLE_PLUGINS = [];
private static readonly string DATA_DIR = SettingsManager.DataDirectory!; private static bool IS_INITIALIZED;
private static string DATA_DIR = string.Empty;
private static readonly string PLUGINS_ROOT = Path.Join(DATA_DIR, "plugins"); private static string PLUGINS_ROOT = string.Empty;
private static string INTERNAL_PLUGINS_ROOT = string.Empty;
private static readonly string INTERNAL_PLUGINS_ROOT = Path.Join(PLUGINS_ROOT, ".internal"); private static FileSystemWatcher HOT_RELOAD_WATCHER = null!;
private static readonly FileSystemWatcher HOT_RELOAD_WATCHER;
private static readonly List<IPluginMetadata> AVAILABLE_PLUGINS = [];
/// <summary> /// <summary>
/// A list of all available plugins. /// A list of all available plugins.
/// </summary> /// </summary>
public static IReadOnlyCollection<IPluginMetadata> AvailablePlugins => AVAILABLE_PLUGINS; public static IReadOnlyCollection<IPluginMetadata> AvailablePlugins => AVAILABLE_PLUGINS;
/// <summary>
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.
/// </summary>
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)) if (!Directory.Exists(PLUGINS_ROOT))
Directory.CreateDirectory(PLUGINS_ROOT); Directory.CreateDirectory(PLUGINS_ROOT);
HOT_RELOAD_WATCHER = new(PLUGINS_ROOT); HOT_RELOAD_WATCHER = new(PLUGINS_ROOT);
IS_INITIALIZED = true;
} }
/// <summary> /// <summary>
@ -48,6 +53,12 @@ public static partial class PluginFactory
/// </remarks> /// </remarks>
public static async Task LoadAll(CancellationToken cancellationToken = default) 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."); LOG.LogInformation("Start loading plugins.");
if (!Directory.Exists(PLUGINS_ROOT)) if (!Directory.Exists(PLUGINS_ROOT))
{ {
@ -151,6 +162,9 @@ public static partial class PluginFactory
public static void Dispose() public static void Dispose()
{ {
if(!IS_INITIALIZED)
return;
HOT_RELOAD_WATCHER.Dispose(); HOT_RELOAD_WATCHER.Dispose();
} }
} }