using System.Reflection; using Inspectron.Settings; using Ninject; using Serilog; using VisionBuilder.UI.Common.Attributes; namespace VisionBuilder.UI.Common.Plugins; [ModulePriority(1000)] public class PluginLoader:IVisionBuilderModule { private readonly PluginSettings _settings; const string PLUGINS_DIRECTORY = "Plugins"; public PluginLoader(PluginSettings settings) { _settings = settings; } public List Plugins { get; } = new List(); private bool _isInitialized; public void InitializeModule() { if (_isInitialized) { return; } _isInitialized = true; Log.Information("Loading plugins..."); var pluginsPath = Path.Combine("..", "Data", PLUGINS_DIRECTORY); Directory.CreateDirectory(pluginsPath); var pluginFolders = Directory.GetDirectories(pluginsPath); foreach (string folder in pluginFolders) { var pluginName = Path.GetFileNameWithoutExtension(folder); if (_settings.Plugins.All(p => p.Name != pluginName)) { Log.Warning("Discovered new plugin:{PluginName}. Adding to settings and skipping.", pluginName); _settings.Plugins.Add(new PluginSettings.PluginFlag { Name = pluginName, Enabled = false }); continue; } if (_settings.Plugins.Where(p => p.Name == pluginName).All(x=>!x.Enabled)) { Log.Information("Skipping plugin {PluginName} as it is not enabled in settings.", pluginName); continue; } var assemblyPath = Path.Combine(folder, Path.GetFileNameWithoutExtension(folder) + ".dll"); if (!File.Exists(assemblyPath)) { Log.Warning("Plugin assembly not found: {AssemblyPath}", assemblyPath); continue; } try { LoadPluginAssembly(assemblyPath); } catch (Exception ex) { Log.Error(ex, "Failed to load plugin from {AssemblyPath}", assemblyPath); } } Log.Information("Plugin loading completed."); } private void LoadPluginAssembly(string assemblyPath) { var absPath = Path.GetFullPath(assemblyPath); var loadContext = new PluginLoadContext(absPath); var assembly = loadContext.LoadFromAssemblyPath(absPath); Log.Information("Loaded plugin assembly: {AssemblyName}", assembly.GetName().Name); foreach (var type in assembly.GetTypes()) { if (type.IsAssignableTo(typeof(IPlugin)) && !type.IsAbstract) { Plugins.Add((IPlugin)Activator.CreateInstance(type)); Log.Information("Loaded plugin: {PluginName}", type.Name); } } } }