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 { const string PLUGINS_DIRECTORY = "Plugins"; public List Plugins { get; } = new List(); private bool _isInitialized; private string _pluginsProfile = "enabled_plugins.txt"; public void InitializeModule(string? pluginsProfile) { if (pluginsProfile != null) _pluginsProfile = pluginsProfile + ".txt"; InitializeModule(); } public void InitializeModule() { if (_isInitialized) { return; } _isInitialized = true; Log.Information("Loading plugins..."); var pluginsPath = Path.Combine("..", "Data", PLUGINS_DIRECTORY); var enabledPluginsPath = Path.Combine(pluginsPath, _pluginsProfile); if (!File.Exists(enabledPluginsPath)) { Log.Warning("Enabled plugins file not found: {EnabledPluginsPath}. All discovered plugins will be disabled by default.", enabledPluginsPath); File.WriteAllText(enabledPluginsPath, ""); } List enabledPlugins = File.ReadAllLines(enabledPluginsPath).ToList(); Directory.CreateDirectory(pluginsPath); var pluginFolders = Directory.GetDirectories(pluginsPath); foreach (string folder in pluginFolders) { var pluginName = Path.GetFileNameWithoutExtension(folder); if (!enabledPlugins.Contains(pluginName)) { 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.FullName); } } } }