diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj
index f3f636825..7e8af7b5f 100644
--- a/src/Artemis.Core/Artemis.Core.csproj
+++ b/src/Artemis.Core/Artemis.Core.csproj
@@ -51,6 +51,9 @@
MinimumRecommendedRules.ruleset
+
+ ..\packages\AppDomainToolkit.1.0.4.3\lib\net\AppDomainToolkit.dll
+
..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll
diff --git a/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs b/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs
index 50c4b9fbd..8b719727d 100644
--- a/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs
+++ b/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs
@@ -18,7 +18,7 @@ namespace Artemis.Core.Plugins.Abstract
public abstract bool ExpandsMainDataModel { get; }
///
- public void LoadPlugin()
+ public void EnablePlugin()
{
// Load and activate the last active profile
}
diff --git a/src/Artemis.Core/Plugins/Interfaces/IPlugin.cs b/src/Artemis.Core/Plugins/Interfaces/IPlugin.cs
index f9ef4fd99..238122061 100644
--- a/src/Artemis.Core/Plugins/Interfaces/IPlugin.cs
+++ b/src/Artemis.Core/Plugins/Interfaces/IPlugin.cs
@@ -10,6 +10,6 @@ namespace Artemis.Core.Plugins.Interfaces
///
/// Called when the plugin is loaded
///
- void LoadPlugin();
+ void EnablePlugin();
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Plugins/Models/PluginInfo.cs b/src/Artemis.Core/Plugins/Models/PluginInfo.cs
index c11d66f61..8cba360d8 100644
--- a/src/Artemis.Core/Plugins/Models/PluginInfo.cs
+++ b/src/Artemis.Core/Plugins/Models/PluginInfo.cs
@@ -1,5 +1,5 @@
using System;
-using System.Collections.Generic;
+using AppDomainToolkit;
using Artemis.Core.Plugins.Interfaces;
using Newtonsoft.Json;
@@ -7,11 +7,6 @@ namespace Artemis.Core.Plugins.Models
{
public class PluginInfo
{
- public PluginInfo()
- {
- Instances = new List();
- }
-
///
/// The plugins GUID
///
@@ -39,10 +34,21 @@ namespace Artemis.Core.Plugins.Models
public string Folder { get; set; }
///
- /// A references to the types implementing IPlugin, available after successful load
+ /// A reference to the type implementing IPlugin, available after successful load
///
[JsonIgnore]
- public List Instances { get; set; }
+ public IPlugin Instance { get; set; }
+
+ ///
+ /// Indicates whether the user enabled the plugin or not
+ ///
+ [JsonIgnore]
+ public bool Enabled { get; set; }
+
+ ///
+ /// The AppDomain context of this plugin
+ ///
+ internal AppDomainContext Context { get; set; }
public override string ToString()
{
diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs
index 874c53452..48ec8119d 100644
--- a/src/Artemis.Core/Services/CoreService.cs
+++ b/src/Artemis.Core/Services/CoreService.cs
@@ -48,7 +48,7 @@ namespace Artemis.Core.Services
{
try
{
- var modules = _pluginService.Plugins.SelectMany(p => p.Instances).OfType().ToList();
+ var modules = _pluginService.GetModules();
// Update all active modules
foreach (var module in modules)
diff --git a/src/Artemis.Core/Services/Interfaces/IPluginService.cs b/src/Artemis.Core/Services/Interfaces/IPluginService.cs
index 602f37cc6..85e6bde9d 100644
--- a/src/Artemis.Core/Services/Interfaces/IPluginService.cs
+++ b/src/Artemis.Core/Services/Interfaces/IPluginService.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using Artemis.Core.Events;
@@ -45,5 +46,11 @@ namespace Artemis.Core.Services.Interfaces
/// The GUID of the layer type to find
/// An instance of the layer type
ILayerType GetLayerTypeByGuid(Guid layerTypeGuid);
+
+ ///
+ /// Returns all the plugins implementing
+ ///
+ ///
+ IReadOnlyList GetModules();
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/PluginService.cs b/src/Artemis.Core/Services/PluginService.cs
index 080a30fb5..d7ecb467d 100644
--- a/src/Artemis.Core/Services/PluginService.cs
+++ b/src/Artemis.Core/Services/PluginService.cs
@@ -3,8 +3,8 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
-using System.Reflection;
using System.Threading.Tasks;
+using AppDomainToolkit;
using Artemis.Core.Events;
using Artemis.Core.Exceptions;
using Artemis.Core.Plugins.Exceptions;
@@ -53,7 +53,6 @@ namespace Artemis.Core.Services
// Load the plugin assemblies into the plugin context
var directory = new DirectoryInfo(Path.Combine(Constants.DataFolder, "plugins"));
foreach (var subDirectory in directory.EnumerateDirectories())
- {
try
{
// Load the metadata
@@ -63,42 +62,58 @@ namespace Artemis.Core.Services
// Locate the main entry
var pluginInfo = JsonConvert.DeserializeObject(File.ReadAllText(metadataFile));
+ // TODO Just temporarily until settings are in place
+ pluginInfo.Enabled = true;
var mainFile = Path.Combine(subDirectory.FullName, pluginInfo.Main);
if (!File.Exists(mainFile))
throw new ArtemisPluginException(pluginInfo, "Couldn't find the plugins main entry at " + mainFile);
// Load the plugin, all types implementing IPlugin and register them with DI
- Assembly assembly;
+ var setupInfo = new AppDomainSetup
+ {
+ ApplicationName = pluginInfo.Guid.ToString(),
+ ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
+ PrivateBinPath = subDirectory.FullName
+ };
+ pluginInfo.Context = AppDomainContext.Create(setupInfo);
+
try
{
- assembly = Assembly.LoadFile(mainFile);
+ pluginInfo.Context.LoadAssemblyWithReferences(LoadMethod.LoadFrom, mainFile);
}
catch (Exception e)
{
throw new ArtemisPluginException(pluginInfo, "Failed to load the plugins assembly", e);
}
- var pluginTypes = assembly.GetTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t)).ToArray();
- foreach (var pluginType in pluginTypes)
- {
- _childKernel.Bind().To(pluginType).InSingletonScope();
- try
- {
- pluginInfo.Instances.Add((IPlugin) _childKernel.Get(pluginType));
- }
- catch (Exception e)
- {
- throw new ArtemisPluginException(pluginInfo, "Failed to instantiate the plugin", e);
- }
- }
+ // Get the IPlugin implementation from the main assembly and if there is only one, instantiate it
+ var mainAssembly = pluginInfo.Context.Domain.GetAssemblies().First(a => a.Location == mainFile);
+ var pluginTypes = mainAssembly.GetTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t)).ToList();
+ if (pluginTypes.Count > 1)
+ throw new ArtemisPluginException(pluginInfo, $"Plugin contains {pluginTypes.Count} implementations of IPlugin, only 1 allowed");
+ if (pluginTypes.Count == 0)
+ throw new ArtemisPluginException(pluginInfo, "Plugin contains no implementation of IPlugin");
+ var pluginType = pluginTypes.Single();
+ _childKernel.Bind().To(pluginType).InSingletonScope();
+ try
+ {
+ pluginInfo.Instance = (IPlugin) _childKernel.Get(pluginType);
+ }
+ catch (Exception e)
+ {
+ throw new ArtemisPluginException(pluginInfo, "Failed to instantiate the plugin", e);
+ }
_plugins.Add(pluginInfo);
}
catch (Exception e)
{
throw new ArtemisPluginException("Failed to load plugin", e);
}
- }
+
+ // Activate plugins after they are all loaded
+ foreach (var pluginInfo in _plugins.Where(p => p.Enabled))
+ pluginInfo.Instance.EnablePlugin();
});
OnFinishedLoadedPlugins();
@@ -111,11 +126,15 @@ namespace Artemis.Core.Services
if (pluginInfo == null)
return null;
- var layerType = pluginInfo.Instances.SingleOrDefault(p => p is ILayerType);
- if (layerType == null)
+ if (!(pluginInfo.Instance is ILayerType layerType))
throw new ArtemisPluginException(pluginInfo, "Plugin is expected to implement exactly one ILayerType");
- return (ILayerType) layerType;
+ return layerType;
+ }
+
+ public IReadOnlyList GetModules()
+ {
+ return Plugins.Where(p => p.Instance is IModule).Select(p => (IModule) p.Instance).ToList();
}
public void Dispose()
diff --git a/src/Artemis.Core/app.config b/src/Artemis.Core/app.config
index ec91ee1d6..58347c373 100644
--- a/src/Artemis.Core/app.config
+++ b/src/Artemis.Core/app.config
@@ -28,8 +28,7 @@
-
+
@@ -53,8 +52,7 @@
-
+
@@ -70,8 +68,7 @@
-
+
@@ -87,8 +84,7 @@
-
+
@@ -96,8 +92,7 @@
-
+
diff --git a/src/Artemis.Core/packages.config b/src/Artemis.Core/packages.config
index 411ff3c70..ce487c687 100644
--- a/src/Artemis.Core/packages.config
+++ b/src/Artemis.Core/packages.config
@@ -1,6 +1,6 @@
-
+
diff --git a/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerTypes.Brush.csproj b/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerTypes.Brush.csproj
index d2008d288..d75cc3ea1 100644
--- a/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerTypes.Brush.csproj
+++ b/src/Artemis.Plugins.LayerTypes.Brush/Artemis.Plugins.LayerTypes.Brush.csproj
@@ -33,17 +33,23 @@
+
+ ..\packages\QRCoder.1.2.5\lib\net40\QRCoder.dll
+
..\packages\RGB.NET.Core.0.1.22\lib\net45\RGB.NET.Core.dll
+ False
..\packages\Stylet.1.1.22\lib\net45\Stylet.dll
+ False
..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll
+ False
@@ -52,6 +58,9 @@
+
+ ..\packages\QRCoder.1.2.5\lib\net40\UnityEngine.dll
+
@@ -63,6 +72,7 @@
{9b811f9b-86b9-4771-87af-72bae7078a36}
Artemis.Core
+ False
diff --git a/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerType.cs b/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerType.cs
index 10a6bbc6a..67aa2b011 100644
--- a/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerType.cs
+++ b/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerType.cs
@@ -1,7 +1,7 @@
-using System;
-using System.Drawing;
+using System.Drawing;
using Artemis.Core.Plugins.Interfaces;
using Artemis.Core.ProfileElements;
+using QRCoder;
using RGB.NET.Core;
namespace Artemis.Plugins.LayerTypes.Brush
@@ -10,12 +10,11 @@ namespace Artemis.Plugins.LayerTypes.Brush
{
public void Dispose()
{
- throw new NotImplementedException();
}
- public void LoadPlugin()
+ public void EnablePlugin()
{
- throw new NotImplementedException();
+ var qrGenerator = new QRCodeGenerator();
}
public void Update(Layer layer)
diff --git a/src/Artemis.Plugins.LayerTypes.Brush/packages.config b/src/Artemis.Plugins.LayerTypes.Brush/packages.config
index ac354a2d0..f559146e0 100644
--- a/src/Artemis.Plugins.LayerTypes.Brush/packages.config
+++ b/src/Artemis.Plugins.LayerTypes.Brush/packages.config
@@ -1,6 +1,7 @@
-
+
+
\ No newline at end of file
diff --git a/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj b/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj
index 3ab93ac6f..947614257 100644
--- a/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj
+++ b/src/Artemis.Plugins.Modules.General/Artemis.Plugins.Modules.General.csproj
@@ -33,17 +33,27 @@
+
+ ..\packages\QRCoder.1.3.5\lib\net40\QRCoder.dll
+
..\packages\RGB.NET.Core.0.1.22\lib\net45\RGB.NET.Core.dll
+ False
-
- ..\packages\Stylet.1.1.22\lib\net45\Stylet.dll
+
+ ..\packages\Stylet.1.1.17\lib\net45\Stylet.dll
+ False
+
+ ..\packages\System.Drawing.Common.4.5.0\lib\net461\System.Drawing.Common.dll
+ False
+
..\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll
+ False
@@ -69,6 +79,7 @@
{9b811f9b-86b9-4771-87af-72bae7078a36}
Artemis.Core
+ False
diff --git a/src/Artemis.Plugins.Modules.General/GeneralDataModel.cs b/src/Artemis.Plugins.Modules.General/GeneralDataModel.cs
index f00c82340..14e360b3c 100644
--- a/src/Artemis.Plugins.Modules.General/GeneralDataModel.cs
+++ b/src/Artemis.Plugins.Modules.General/GeneralDataModel.cs
@@ -6,11 +6,11 @@ namespace Artemis.Plugins.Modules.General
{
public class GeneralDataModel : ModuleDataModel
{
- [DataModelProperty(DisplayName = "Unique boolean")]
- public bool PropertyUniqueToThisDm { get; set; }
-
public GeneralDataModel(IModule module) : base(module)
{
}
+
+ [DataModelProperty(DisplayName = "Unique boolean")]
+ public bool PropertyUniqueToThisDm { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Artemis.Plugins.Modules.General/GeneralModule.cs b/src/Artemis.Plugins.Modules.General/GeneralModule.cs
index a5089b49c..cafc22e97 100644
--- a/src/Artemis.Plugins.Modules.General/GeneralModule.cs
+++ b/src/Artemis.Plugins.Modules.General/GeneralModule.cs
@@ -4,6 +4,7 @@ using Artemis.Core;
using Artemis.Core.Plugins.Interfaces;
using Artemis.Core.Services.Interfaces;
using Artemis.Plugins.Modules.General.ViewModels;
+using QRCoder;
using RGB.NET.Core;
using Stylet;
using Color = System.Drawing.Color;
@@ -63,8 +64,9 @@ namespace Artemis.Plugins.Modules.General
_colors = null;
}
- public void LoadPlugin()
+ public void EnablePlugin()
{
+ var qrGenerator = new QRCodeGenerator();
PopulateColors();
}
diff --git a/src/Artemis.Plugins.Modules.General/packages.config b/src/Artemis.Plugins.Modules.General/packages.config
index 3bd1a62d7..a2474caba 100644
--- a/src/Artemis.Plugins.Modules.General/packages.config
+++ b/src/Artemis.Plugins.Modules.General/packages.config
@@ -1,7 +1,8 @@
-
+
-
+
+
\ No newline at end of file
diff --git a/src/Artemis.UI/App.config b/src/Artemis.UI/App.config
index fcbfc6adb..39dcaca51 100644
--- a/src/Artemis.UI/App.config
+++ b/src/Artemis.UI/App.config
@@ -31,8 +31,7 @@
-
+
@@ -56,8 +55,7 @@
-
+
@@ -73,8 +71,7 @@
-
+
@@ -90,8 +87,7 @@
-
+
@@ -99,8 +95,7 @@
-
+
diff --git a/src/Artemis.UI/ViewModels/RootViewModel.cs b/src/Artemis.UI/ViewModels/RootViewModel.cs
index 4b6376768..a62f43220 100644
--- a/src/Artemis.UI/ViewModels/RootViewModel.cs
+++ b/src/Artemis.UI/ViewModels/RootViewModel.cs
@@ -34,7 +34,7 @@ namespace Artemis.UI.ViewModels
_pluginService.FinishedLoadedPlugins += PluginServiceOnFinishedLoadedPlugins;
if (!LoadingPlugins)
- Modules.AddRange(_pluginService.Plugins.SelectMany(p => p.Instances.Where(i => i is IModule).Cast()));
+ Modules.AddRange(_pluginService.GetModules());
PropertyChanged += OnSelectedModuleChanged;
PropertyChanged += OnSelectedPageChanged;
@@ -58,7 +58,7 @@ namespace Artemis.UI.ViewModels
private void PluginServiceOnFinishedLoadedPlugins(object sender, EventArgs eventArgs)
{
- Modules.AddRange(_pluginService.Plugins.SelectMany(p => p.Instances.Where(i => i is IModule).Cast()));
+ Modules.AddRange(_pluginService.GetModules());
SelectedModule = null;
LoadingPlugins = false;