diff --git a/src/Artemis.Core/Ninject/PluginModule.cs b/src/Artemis.Core/Ninject/PluginModule.cs
new file mode 100644
index 000000000..bd1b81ddd
--- /dev/null
+++ b/src/Artemis.Core/Ninject/PluginModule.cs
@@ -0,0 +1,19 @@
+using System;
+using Ninject.Modules;
+
+namespace Artemis.Core.Ninject
+{
+ internal class PluginModule : NinjectModule
+ {
+ public PluginModule(PluginInfo pluginInfo)
+ {
+ PluginInfo = pluginInfo ?? throw new ArgumentNullException(nameof(pluginInfo));
+ }
+
+ public PluginInfo PluginInfo { get; }
+
+ public override void Load()
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Plugins/LayerBrushes/BrushConfigurationViewModel.cs b/src/Artemis.Core/Plugins/LayerBrushes/BrushConfigurationViewModel.cs
index 16915f0a2..34a928f94 100644
--- a/src/Artemis.Core/Plugins/LayerBrushes/BrushConfigurationViewModel.cs
+++ b/src/Artemis.Core/Plugins/LayerBrushes/BrushConfigurationViewModel.cs
@@ -16,6 +16,16 @@ namespace Artemis.Core.LayerBrushes
LayerBrush = layerBrush;
}
+ ///
+ /// Creates a new instance of the class with a validator
+ ///
+ ///
+ ///
+ protected BrushConfigurationViewModel(BaseLayerBrush layerBrush, IModelValidator validator) : base(validator)
+ {
+ LayerBrush = layerBrush;
+ }
+
///
/// Gets the layer brush this view model is associated with
///
diff --git a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs b/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs
index abea15d1c..8524c5de1 100644
--- a/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs
+++ b/src/Artemis.Core/Plugins/LayerBrushes/LayerBrushDescriptor.cs
@@ -62,7 +62,7 @@ namespace Artemis.Core.LayerBrushes
if (layer.LayerBrush != null)
throw new ArtemisCoreException("Layer already has an instantiated layer brush");
- var brush = (BaseLayerBrush) CoreService.Kernel.Get(LayerBrushType);
+ var brush = (BaseLayerBrush) LayerBrushProvider.PluginInfo.Kernel.Get(LayerBrushType);
brush.Layer = layer;
brush.Descriptor = this;
brush.Initialize();
diff --git a/src/Artemis.Core/Plugins/LayerEffects/EffectConfigurationViewModel.cs b/src/Artemis.Core/Plugins/LayerEffects/EffectConfigurationViewModel.cs
index 472f947ea..effc967a3 100644
--- a/src/Artemis.Core/Plugins/LayerEffects/EffectConfigurationViewModel.cs
+++ b/src/Artemis.Core/Plugins/LayerEffects/EffectConfigurationViewModel.cs
@@ -16,6 +16,16 @@ namespace Artemis.Core.LayerEffects
LayerEffect = layerEffect;
}
+ ///
+ /// Creates a new instance of the class with a validator
+ ///
+ ///
+ ///
+ protected EffectConfigurationViewModel(BaseLayerEffect layerEffect, IModelValidator validator) : base(validator)
+ {
+ LayerEffect = layerEffect;
+ }
+
///
/// Gets the layer effect this view model is associated with
///
diff --git a/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs b/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs
index 50ffaa310..d913de153 100644
--- a/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs
+++ b/src/Artemis.Core/Plugins/LayerEffects/LayerEffectDescriptor.cs
@@ -46,7 +46,7 @@ namespace Artemis.Core.LayerEffects
/// The plugin that provided this
///
public LayerEffectProvider LayerEffectProvider { get; }
-
+
///
/// Gets the GUID this descriptor is acting as a placeholder for. If null, this descriptor is not a placeholder
///
@@ -67,7 +67,7 @@ namespace Artemis.Core.LayerEffects
return;
}
- var effect = (BaseLayerEffect)CoreService.Kernel.Get(LayerEffectType);
+ var effect = (BaseLayerEffect) LayerEffectProvider.PluginInfo.Kernel.Get(LayerEffectType);
effect.ProfileElement = renderElement;
effect.EntityId = entity.Id;
effect.Order = entity.Order;
diff --git a/src/Artemis.Core/Plugins/PluginConfigurationViewModel.cs b/src/Artemis.Core/Plugins/PluginConfigurationViewModel.cs
index 731dc1b3f..ea4169732 100644
--- a/src/Artemis.Core/Plugins/PluginConfigurationViewModel.cs
+++ b/src/Artemis.Core/Plugins/PluginConfigurationViewModel.cs
@@ -16,6 +16,16 @@ namespace Artemis.Core
Plugin = plugin;
}
+ ///
+ /// Creates a new instance of the class with a validator
+ ///
+ ///
+ ///
+ protected PluginConfigurationViewModel(Plugin plugin, IModelValidator validator) : base(validator)
+ {
+ Plugin = plugin;
+ }
+
///
/// Gets the plugin this configuration view model is associated with
///
diff --git a/src/Artemis.Core/Plugins/PluginInfo.cs b/src/Artemis.Core/Plugins/PluginInfo.cs
index 28646a2da..414b33d44 100644
--- a/src/Artemis.Core/Plugins/PluginInfo.cs
+++ b/src/Artemis.Core/Plugins/PluginInfo.cs
@@ -4,6 +4,8 @@ using System.Reflection;
using Artemis.Storage.Entities.Plugins;
using McMaster.NETCore.Plugins;
using Newtonsoft.Json;
+using Ninject;
+using Ninject.Extensions.ChildKernel;
using Stylet;
namespace Artemis.Core
@@ -135,13 +137,18 @@ namespace Artemis.Core
///
/// The assembly the plugin code lives in
///
- internal Assembly Assembly { get; set; }
+ public Assembly Assembly { get; internal set; }
+
+ ///
+ /// The Ninject kernel of the plugin
+ ///
+ public IKernel Kernel { get; internal set; }
///
/// The entity representing the plugin
///
internal PluginEntity PluginEntity { get; set; }
-
+
///
public override string ToString()
{
diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs
index e981a567e..a7a010118 100644
--- a/src/Artemis.Core/Services/CoreService.cs
+++ b/src/Artemis.Core/Services/CoreService.cs
@@ -41,6 +41,8 @@ namespace Artemis.Core.Services
IRgbService rgbService, ISurfaceService surfaceService, IProfileService profileService, IModuleService moduleService)
{
Kernel = kernel;
+ Constants.CorePluginInfo.Kernel = kernel;
+
_logger = logger;
_pluginService = pluginService;
_rgbService = rgbService;
diff --git a/src/Artemis.Core/Services/PluginService.cs b/src/Artemis.Core/Services/PluginService.cs
index 0fd4e3574..4eae4f677 100644
--- a/src/Artemis.Core/Services/PluginService.cs
+++ b/src/Artemis.Core/Services/PluginService.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using Artemis.Core.DeviceProviders;
+using Artemis.Core.Ninject;
using Artemis.Storage.Entities.Plugins;
using Artemis.Storage.Repositories.Interfaces;
using McMaster.NETCore.Plugins;
@@ -25,7 +26,6 @@ namespace Artemis.Core.Services
private readonly ILogger _logger;
private readonly IPluginRepository _pluginRepository;
private readonly List _plugins;
- private IKernel _childKernel;
public PluginService(IKernel kernel, ILogger logger, IPluginRepository pluginRepository)
{
@@ -110,9 +110,6 @@ namespace Artemis.Core.Services
// Unload all currently loaded plugins first
UnloadPlugins();
- // Create a child kernel and app domain that will only contain the plugins
- _childKernel = new ChildKernel(_kernel);
-
// Load the plugin assemblies into the plugin context
var pluginDirectory = new DirectoryInfo(Path.Combine(Constants.DataFolder, "plugins"));
foreach (var subDirectory in pluginDirectory.EnumerateDirectories())
@@ -160,13 +157,6 @@ namespace Artemis.Core.Services
while (_plugins.Count > 0)
UnloadPlugin(_plugins[0]);
- // Dispose the child kernel and therefore any leftover plugins instantiated with it
- if (_childKernel != null)
- {
- _childKernel.Dispose();
- _childKernel = null;
- }
-
_plugins.Clear();
}
}
@@ -232,7 +222,9 @@ namespace Artemis.Core.Services
{
new Parameter("PluginInfo", pluginInfo, false)
};
- pluginInfo.Instance = (Plugin) _childKernel.Get(pluginType, constraint: null, parameters: parameters);
+ pluginInfo.Kernel = new ChildKernel(_kernel);
+ pluginInfo.Kernel.Load(new PluginModule(pluginInfo));
+ pluginInfo.Instance = (Plugin) pluginInfo.Kernel.Get(pluginType, constraint: null, parameters: parameters);
pluginInfo.Instance.PluginInfo = pluginInfo;
}
catch (Exception e)
@@ -262,10 +254,10 @@ namespace Artemis.Core.Services
OnPluginDisabled(new PluginEventArgs(pluginInfo));
}
- _childKernel.Unbind(pluginInfo.Instance.GetType());
-
pluginInfo.Instance.Dispose();
pluginInfo.PluginLoader.Dispose();
+ pluginInfo.Kernel.Dispose();
+
_plugins.Remove(pluginInfo);
OnPluginUnloaded(new PluginEventArgs(pluginInfo));
diff --git a/src/Artemis.UI.Shared/Services/DataModelUIService.cs b/src/Artemis.UI.Shared/Services/DataModelUIService.cs
index e56b5f697..d3f35326d 100644
--- a/src/Artemis.UI.Shared/Services/DataModelUIService.cs
+++ b/src/Artemis.UI.Shared/Services/DataModelUIService.cs
@@ -58,7 +58,7 @@ namespace Artemis.UI.Shared.Services
return mainDataModel;
}
-
+
var dataModel = _dataModelService.GetPluginDataModel(plugin);
if (dataModel == null)
return null;
@@ -71,7 +71,7 @@ namespace Artemis.UI.Shared.Services
viewModel.UpdateRequested += (sender, args) => viewModel.Update(this);
return viewModel;
}
-
+
public DataModelVisualizationRegistration RegisterDataModelInput(PluginInfo pluginInfo, IReadOnlyCollection compatibleConversionTypes = null) where T : DataModelInputViewModel
{
if (compatibleConversionTypes == null)
@@ -165,7 +165,7 @@ namespace Artemis.UI.Shared.Services
{
var match = _registeredDataModelDisplays.FirstOrDefault(d => d.SupportedType == propertyType);
if (match != null)
- return (DataModelDisplayViewModel) _kernel.Get(match.ViewModelType);
+ return (DataModelDisplayViewModel) match.PluginInfo.Kernel.Get(match.ViewModelType);
return !fallBackToDefault ? null : _kernel.Get();
}
}
@@ -222,7 +222,7 @@ namespace Artemis.UI.Shared.Services
new ConstructorArgument("description", description),
new ConstructorArgument("initialValue", initialValue)
};
- var viewModel = (DataModelInputViewModel) _kernel.Get(registration.ViewModelType, parameters);
+ var viewModel = (DataModelInputViewModel) registration.PluginInfo.Kernel.Get(registration.ViewModelType, parameters);
viewModel.CompatibleConversionTypes = registration.CompatibleConversionTypes;
return viewModel;
}
diff --git a/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs b/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs
index cd160e0cf..84b8e259d 100644
--- a/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs
+++ b/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs
@@ -11,6 +11,7 @@ using Stylet;
namespace Artemis.UI.Shared.Services
{
+ // TODO: Become plugin-aware and use plugin kernel if injected into a plugin
internal class DialogService : IDialogService
{
private readonly IKernel _kernel;
diff --git a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs
index 674e98223..afdc19069 100644
--- a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs
+++ b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs
@@ -273,7 +273,8 @@ namespace Artemis.UI.Shared.Services
return null;
var parameter = new ConstructorArgument("layerProperty", layerProperty);
- return (PropertyInputViewModel) Kernel.Get(viewModelType, parameter);
+ var kernel = registration != null ? registration.PluginInfo.Kernel : Kernel;
+ return (PropertyInputViewModel) kernel.Get(viewModelType, parameter);
}
public ProfileModule GetCurrentModule()
diff --git a/src/Artemis.UI/Ninject/PluginUIModule.cs b/src/Artemis.UI/Ninject/PluginUIModule.cs
new file mode 100644
index 000000000..5cccc2033
--- /dev/null
+++ b/src/Artemis.UI/Ninject/PluginUIModule.cs
@@ -0,0 +1,32 @@
+using System;
+using Artemis.Core;
+using Artemis.UI.Stylet;
+using FluentValidation;
+using Ninject.Extensions.Conventions;
+using Ninject.Modules;
+using Stylet;
+
+namespace Artemis.UI.Ninject
+{
+ public class PluginUIModule : NinjectModule
+ {
+ public PluginUIModule(PluginInfo pluginInfo)
+ {
+ PluginInfo = pluginInfo ?? throw new ArgumentNullException(nameof(pluginInfo));
+ }
+
+ public PluginInfo PluginInfo { get; }
+
+ public override void Load()
+ {
+ Bind(typeof(IModelValidator<>)).To(typeof(FluentValidationAdapter<>));
+ Kernel.Bind(x =>
+ {
+ x.From(PluginInfo.Assembly)
+ .SelectAllClasses()
+ .InheritedFrom()
+ .BindAllInterfaces();
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Ninject/UiModule.cs b/src/Artemis.UI/Ninject/UiModule.cs
index 3d807d1d9..9bfa0a102 100644
--- a/src/Artemis.UI/Ninject/UiModule.cs
+++ b/src/Artemis.UI/Ninject/UiModule.cs
@@ -14,7 +14,6 @@ using Stylet;
namespace Artemis.UI.Ninject
{
- // ReSharper disable once InconsistentNaming
public class UIModule : NinjectModule
{
public override void Load()
diff --git a/src/Artemis.UI/Screens/Modules/ModuleRootViewModel.cs b/src/Artemis.UI/Screens/Modules/ModuleRootViewModel.cs
index 402c3412c..d8086b15f 100644
--- a/src/Artemis.UI/Screens/Modules/ModuleRootViewModel.cs
+++ b/src/Artemis.UI/Screens/Modules/ModuleRootViewModel.cs
@@ -10,16 +10,14 @@ namespace Artemis.UI.Screens.Modules
{
public class ModuleRootViewModel : Conductor.Collection.OneActive
{
- private readonly IKernel _kernel;
private readonly IModuleVmFactory _moduleVmFactory;
- public ModuleRootViewModel(Module module, IModuleVmFactory moduleVmFactory, IKernel kernel)
+ public ModuleRootViewModel(Module module, IModuleVmFactory moduleVmFactory)
{
DisplayName = module?.DisplayName;
Module = module;
_moduleVmFactory = moduleVmFactory;
- _kernel = kernel;
}
public Module Module { get; }
@@ -47,7 +45,7 @@ namespace Artemis.UI.Screens.Modules
var module = new ConstructorArgument("module", Module);
var displayName = new ConstructorArgument("displayName", DisplayName);
- var viewModel = (ModuleViewModel) _kernel.Get(moduleTab.Type, module, displayName);
+ var viewModel = (ModuleViewModel) Module.PluginInfo.Kernel.Get(moduleTab.Type, module, displayName);
Items.Add(viewModel);
}
}
diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeGroupViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeGroupViewModel.cs
index 07eb31138..67dbc1956 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeGroupViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeGroupViewModel.cs
@@ -60,7 +60,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
// Find the BaseLayerBrush parameter, it is required by the base constructor so its there for sure
var brushParameter = constructors.First().GetParameters().First(p => typeof(BaseLayerBrush).IsAssignableFrom(p.ParameterType));
var argument = new ConstructorArgument(brushParameter.Name, layerBrush);
- var viewModel = (BrushConfigurationViewModel) _kernel.Get(configurationViewModel.Type, argument);
+ var viewModel = (BrushConfigurationViewModel) layerBrush.PluginInfo.Kernel.Get(configurationViewModel.Type, argument);
_windowManager.ShowDialog(new LayerBrushSettingsWindowViewModel(viewModel));
}
@@ -86,7 +86,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
var effectParameter = constructors.First().GetParameters().First(p => typeof(BaseLayerEffect).IsAssignableFrom(p.ParameterType));
var argument = new ConstructorArgument(effectParameter.Name, layerEffect);
- var viewModel = (EffectConfigurationViewModel) _kernel.Get(configurationViewModel.Type, argument);
+ var viewModel = (EffectConfigurationViewModel) layerEffect.PluginInfo.Kernel.Get(configurationViewModel.Type, argument);
_windowManager.ShowDialog(new LayerEffectSettingsWindowViewModel(viewModel));
}
catch (Exception e)
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs
index f35cf5a68..0796a1297 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs
@@ -23,7 +23,6 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
public class PluginSettingsViewModel : PropertyChangedBase
{
private readonly IDialogService _dialogService;
- private readonly IKernel _kernel;
private readonly ILogger _logger;
private readonly IPluginService _pluginService;
private readonly ISnackbarMessageQueue _snackbarMessageQueue;
@@ -33,7 +32,6 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
private PluginInfo _pluginInfo;
public PluginSettingsViewModel(Plugin plugin,
- IKernel kernel,
ILogger logger,
IWindowManager windowManager,
IDialogService dialogService,
@@ -43,7 +41,6 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
Plugin = plugin;
PluginInfo = plugin.PluginInfo;
- _kernel = kernel;
_logger = logger;
_windowManager = windowManager;
_dialogService = dialogService;
@@ -96,7 +93,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
var pluginParameter = constructors.First().GetParameters().First(p => typeof(Plugin).IsAssignableFrom(p.ParameterType));
var plugin = new ConstructorArgument(pluginParameter.Name, Plugin);
- var viewModel = (PluginConfigurationViewModel) _kernel.Get(configurationViewModel.Type, plugin);
+ var viewModel = (PluginConfigurationViewModel) PluginInfo.Kernel.Get(configurationViewModel.Type, plugin);
_windowManager.ShowDialog(new PluginSettingsWindowViewModel(viewModel, Icon));
}
catch (Exception e)
diff --git a/src/Artemis.UI/Services/RegistrationService.cs b/src/Artemis.UI/Services/RegistrationService.cs
index 738fae7ea..5e1e44c22 100644
--- a/src/Artemis.UI/Services/RegistrationService.cs
+++ b/src/Artemis.UI/Services/RegistrationService.cs
@@ -1,6 +1,8 @@
using Artemis.Core;
+using Artemis.Core.Services;
using Artemis.UI.DefaultTypes.DataModel.Display;
using Artemis.UI.DefaultTypes.DataModel.Input;
+using Artemis.UI.Ninject;
using Artemis.UI.PropertyInput;
using Artemis.UI.Services.Interfaces;
using Artemis.UI.Shared.Services;
@@ -11,14 +13,19 @@ namespace Artemis.UI.Services
{
private readonly IDataModelUIService _dataModelUIService;
private readonly IProfileEditorService _profileEditorService;
+ private readonly IPluginService _pluginService;
private bool _registeredBuiltInDataModelDisplays;
private bool _registeredBuiltInDataModelInputs;
private bool _registeredBuiltInPropertyEditors;
- public RegistrationService(IDataModelUIService dataModelUIService, IProfileEditorService profileEditorService)
+ public RegistrationService(IDataModelUIService dataModelUIService, IProfileEditorService profileEditorService, IPluginService pluginService)
{
_dataModelUIService = dataModelUIService;
_profileEditorService = profileEditorService;
+ _pluginService = pluginService;
+
+ LoadPluginModules();
+ pluginService.PluginLoaded += PluginServiceOnPluginLoaded;
}
public void RegisterBuiltInDataModelDisplays()
@@ -63,6 +70,17 @@ namespace Artemis.UI.Services
_registeredBuiltInPropertyEditors = true;
}
+
+ private void PluginServiceOnPluginLoaded(object? sender, PluginEventArgs e)
+ {
+ e.PluginInfo.Kernel.Load(new[] { new PluginUIModule(e.PluginInfo) });
+ }
+
+ private void LoadPluginModules()
+ {
+ foreach (var pluginInfo in _pluginService.GetAllPluginInfo())
+ pluginInfo.Kernel.Load(new[] { new PluginUIModule(pluginInfo) });
+ }
}
public interface IRegistrationService : IArtemisUIService