plugin selection
This commit is contained in:
@@ -10,7 +10,7 @@ namespace TestPlugin
|
|||||||
{
|
{
|
||||||
public void InitializeModule()
|
public void InitializeModule()
|
||||||
{
|
{
|
||||||
Console.WriteLine("Global plugin initialized");
|
Console.WriteLine("Global HELLO from test plugin");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ namespace TestPlugin
|
|||||||
{
|
{
|
||||||
public void InitializeModule()
|
public void InitializeModule()
|
||||||
{
|
{
|
||||||
Console.WriteLine("Camera plugin initialized");
|
Console.WriteLine("Camera HELLO from test plugin");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class TestPlugin: IPlugin
|
public class TestPlugin: IPlugin
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace VisionBuilder.UI.Common.Attributes;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class ModulePriorityAttribute: Attribute
|
||||||
|
{
|
||||||
|
public int Priority { get; }
|
||||||
|
|
||||||
|
public ModulePriorityAttribute(int priority)
|
||||||
|
{
|
||||||
|
Priority = priority;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
using Ninject;
|
using Ninject;
|
||||||
using Ninject.Extensions.ChildKernel;
|
using Ninject.Extensions.ChildKernel;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using VisionBuilder.UI.Common.Attributes;
|
||||||
using VisionBuilder.UI.Common.Plugins;
|
using VisionBuilder.UI.Common.Plugins;
|
||||||
|
|
||||||
namespace VisionBuilder.UI.Common;
|
namespace VisionBuilder.UI.Common;
|
||||||
@@ -24,12 +26,23 @@ public static class Extensions
|
|||||||
self.Bind<T, IVisionBuilderModule>().To<T>().InSingletonScope();
|
self.Bind<T, IVisionBuilderModule>().To<T>().InSingletonScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static int GetModulePriority(IVisionBuilderModule module)
|
||||||
|
{
|
||||||
|
var priorityAttribute = module.GetType().GetCustomAttributes(typeof(ModulePriorityAttribute), true)
|
||||||
|
.FirstOrDefault() as ModulePriorityAttribute;
|
||||||
|
return priorityAttribute?.Priority ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Type> _initializedModules = new List<Type>();
|
||||||
|
|
||||||
public static void InitializeModules(this IKernel self)
|
public static void InitializeModules(this IKernel self)
|
||||||
{
|
{
|
||||||
|
|
||||||
var serviceTypes = self.GetAll(typeof(IVisionBuilderModule)).Select(x => (IVisionBuilderModule)x).ToList();
|
var serviceTypes = self.GetAll(typeof(IVisionBuilderModule)).Select(x => (IVisionBuilderModule)x)
|
||||||
|
.Where(x => !_initializedModules.Contains(x.GetType()))
|
||||||
|
.OrderByDescending(GetModulePriority)
|
||||||
|
.ToList();
|
||||||
foreach (var service in serviceTypes)
|
foreach (var service in serviceTypes)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -45,12 +58,22 @@ public static class Extensions
|
|||||||
Log.Error($"Error initializing module {service.GetType().Name}: {e}", e);
|
Log.Error($"Error initializing module {service.GetType().Name}: {e}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_initializedModules.Add(service.GetType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IKernel LoadGlobalPlugins(this IKernel self)
|
public static IKernel UsePlugins(this IKernel self)
|
||||||
{
|
{
|
||||||
var plugins = PluginLoader.Instance.Plugins;
|
TypeDescriptor.AddAttributes(typeof(List<PluginSettings.PluginFlag>), new TypeConverterAttribute(typeof(PluginFlagConverter)));
|
||||||
|
self.Bind<PluginSettings, ISettings>().ToConstant(new PluginSettings());
|
||||||
|
self.RegisterModule<PluginLoader>();
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static IKernel InitializeGlobalPlugins(this IKernel self)
|
||||||
|
{
|
||||||
|
var plugins = self.Get<PluginLoader>().Plugins;
|
||||||
foreach (var plugin in plugins)
|
foreach (var plugin in plugins)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -66,9 +89,9 @@ public static class Extensions
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IKernel LoadCameraPlugins(this IChildKernel self, string cameraName)
|
public static IKernel InitializeCameraPlugins(this IChildKernel self, string cameraName)
|
||||||
{
|
{
|
||||||
var plugins = PluginLoader.Instance.Plugins;
|
var plugins = self.Get<PluginLoader>().Plugins;
|
||||||
foreach (var plugin in plugins)
|
foreach (var plugin in plugins)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -2,32 +2,56 @@
|
|||||||
using Inspectron.Settings;
|
using Inspectron.Settings;
|
||||||
using Ninject;
|
using Ninject;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using VisionBuilder.UI.Common.Attributes;
|
||||||
|
|
||||||
namespace VisionBuilder.UI.Common.Plugins;
|
namespace VisionBuilder.UI.Common.Plugins;
|
||||||
|
|
||||||
public class PluginLoader
|
[ModulePriority(1000)]
|
||||||
|
public class PluginLoader:IVisionBuilderModule
|
||||||
{
|
{
|
||||||
private static PluginLoader _instance;
|
private readonly PluginSettings _settings;
|
||||||
public static PluginLoader Instance => _instance ??= new PluginLoader();
|
|
||||||
|
|
||||||
const string PLUGINS_DIRECTORY = "Plugins";
|
const string PLUGINS_DIRECTORY = "Plugins";
|
||||||
private PluginLoader()
|
public PluginLoader(PluginSettings settings)
|
||||||
{
|
{
|
||||||
Initialize();
|
_settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IPlugin> Plugins { get; } = new List<IPlugin>();
|
public List<IPlugin> Plugins { get; } = new List<IPlugin>();
|
||||||
|
|
||||||
|
private bool _isInitialized;
|
||||||
public void Initialize()
|
public void InitializeModule()
|
||||||
{
|
{
|
||||||
|
if (_isInitialized)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isInitialized = true;
|
||||||
Log.Information("Loading plugins...");
|
Log.Information("Loading plugins...");
|
||||||
var pluginsPath = Path.Combine("..", "Data", PLUGINS_DIRECTORY);
|
var pluginsPath = Path.Combine("..", "Data", PLUGINS_DIRECTORY);
|
||||||
Directory.CreateDirectory(pluginsPath);
|
Directory.CreateDirectory(pluginsPath);
|
||||||
var pluginFolders = Directory.GetDirectories(pluginsPath);
|
var pluginFolders = Directory.GetDirectories(pluginsPath);
|
||||||
|
|
||||||
foreach (string folder in pluginFolders)
|
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");
|
var assemblyPath = Path.Combine(folder, Path.GetFileNameWithoutExtension(folder) + ".dll");
|
||||||
|
|
||||||
if (!File.Exists(assemblyPath))
|
if (!File.Exists(assemblyPath))
|
||||||
@@ -58,10 +82,12 @@ public class PluginLoader
|
|||||||
if (type.IsAssignableTo(typeof(IPlugin)) && !type.IsAbstract)
|
if (type.IsAssignableTo(typeof(IPlugin)) && !type.IsAbstract)
|
||||||
{
|
{
|
||||||
Plugins.Add((IPlugin)Activator.CreateInstance(type));
|
Plugins.Add((IPlugin)Activator.CreateInstance(type));
|
||||||
Log.Information("Discovered plugin: {PluginName}", type.Name);
|
Log.Information("Loaded plugin: {PluginName}", type.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
50
VisionBuilder.UI.Common/Plugins/PluginSettings.cs
Normal file
50
VisionBuilder.UI.Common/Plugins/PluginSettings.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using Inspectron.Settings;
|
||||||
|
using VisionBuilder.UI.Common.Utils;
|
||||||
|
|
||||||
|
namespace VisionBuilder.UI.Common.Plugins;
|
||||||
|
|
||||||
|
public class PluginSettings:ISettings
|
||||||
|
{
|
||||||
|
public class PluginFlag
|
||||||
|
{
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{(Enabled ? "" : "(Disabled)")}{Name}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PluginFlag> Plugins { get; set; } = new List<PluginFlag>();
|
||||||
|
public void RegisterSettings(InspectronSettings settings)
|
||||||
|
{
|
||||||
|
settings.RegisterSimple(this, () => this.Plugins,"Plugins",nameof(Plugins));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PluginFlagConverter : GeneralListTypeConverter<PluginSettings.PluginFlag>
|
||||||
|
{
|
||||||
|
protected override PluginSettings.PluginFlag ConvertFromString(ITypeDescriptorContext context, CultureInfo culture, string stringValue)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(stringValue))
|
||||||
|
return null;
|
||||||
|
var parts = stringValue.Split(',');
|
||||||
|
if (parts.Length == 2)
|
||||||
|
{
|
||||||
|
return new PluginSettings.PluginFlag
|
||||||
|
{
|
||||||
|
Name = parts[0].Trim(),
|
||||||
|
Enabled = bool.Parse(parts[1].Trim())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string ConvertToString(ITypeDescriptorContext context, CultureInfo culture, PluginSettings.PluginFlag errorShortName)
|
||||||
|
{
|
||||||
|
return $"{errorShortName.Name}, {errorShortName.Enabled}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
using Ninject;
|
using Ninject;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using VisionBuilder.UI.Common;
|
using VisionBuilder.UI.Common;
|
||||||
|
using VisionBuilder.UI.Common.Attributes;
|
||||||
|
|
||||||
namespace VisionBuilder.UI.Console
|
namespace VisionBuilder.UI.Console
|
||||||
{
|
{
|
||||||
|
[ModulePriority(100000)]
|
||||||
public class VisionBuilderConsole: IVisionBuilderModule
|
public class VisionBuilderConsole: IVisionBuilderModule
|
||||||
{
|
{
|
||||||
private readonly VisionBuilderConsoleSettings _settings;
|
private readonly VisionBuilderConsoleSettings _settings;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public class IOCommanderModule:IVisionBuilderModule
|
|||||||
|
|
||||||
public void InitializeModule()
|
public void InitializeModule()
|
||||||
{
|
{
|
||||||
|
if(!_settings.Enabled)return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_ioCommander = _factory.Create();
|
_ioCommander = _factory.Create();
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ public class IOCommanderSettings: ISettings
|
|||||||
public int PulseLength { get; set; } = 100;
|
public int PulseLength { get; set; } = 100;
|
||||||
public bool ShowDebugView { get; set; } = false;
|
public bool ShowDebugView { get; set; } = false;
|
||||||
public string Port { get; set; }="COM3";
|
public string Port { get; set; }="COM3";
|
||||||
|
public bool Enabled { get; set; }
|
||||||
|
|
||||||
public List<IOCommanderProcessingEvent> GlobalEvents { get; set; } =
|
public List<IOCommanderProcessingEvent> GlobalEvents { get; set; } =
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ namespace VisionBuilder.UI.Windows.Test
|
|||||||
.UseIOCommanderWindowsDebug()
|
.UseIOCommanderWindowsDebug()
|
||||||
.UseIOCommanderVirtualInput()
|
.UseIOCommanderVirtualInput()
|
||||||
.UseWindowsServices()
|
.UseWindowsServices()
|
||||||
.LoadGlobalPlugins()
|
.UsePlugins()
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
mainKernel.Get<ILoadingService>().StartLoading("Camera initialization");
|
mainKernel.Get<ILoadingService>().StartLoading("Camera initialization");
|
||||||
@@ -64,12 +65,9 @@ namespace VisionBuilder.UI.Windows.Test
|
|||||||
.UseRingbuffer(CAMERA1)
|
.UseRingbuffer(CAMERA1)
|
||||||
.UseHawkeyeRecipes(CAMERA1)
|
.UseHawkeyeRecipes(CAMERA1)
|
||||||
.UseCameraIOCommander(CAMERA1)
|
.UseCameraIOCommander(CAMERA1)
|
||||||
.LoadCameraPlugins(CAMERA1)
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// LOAD SETTINGS //
|
// LOAD SETTINGS //
|
||||||
mainKernel.RegisterSettings();
|
mainKernel.RegisterSettings();
|
||||||
kernelCamera1.RegisterSettings();
|
kernelCamera1.RegisterSettings();
|
||||||
@@ -79,7 +77,16 @@ namespace VisionBuilder.UI.Windows.Test
|
|||||||
// Must be done after settings are loaded
|
// Must be done after settings are loaded
|
||||||
kernelCamera1.UseCamera();
|
kernelCamera1.UseCamera();
|
||||||
|
|
||||||
|
// initialize modules
|
||||||
|
mainKernel.InitializeModules();
|
||||||
|
kernelCamera1.InitializeModules();
|
||||||
|
|
||||||
|
|
||||||
|
settings.LoadSettings(); // load settings for plugins as they are loaded after modules
|
||||||
|
mainKernel.InitializeGlobalPlugins();
|
||||||
|
kernelCamera1.InitializeCameraPlugins(CAMERA1);
|
||||||
|
|
||||||
|
// initialize plugins the same way as modules(loaded modules are skipped)
|
||||||
mainKernel.InitializeModules();
|
mainKernel.InitializeModules();
|
||||||
kernelCamera1.InitializeModules();
|
kernelCamera1.InitializeModules();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user