diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj
index 93bb7c259..399048bda 100644
--- a/src/Artemis.Core/Artemis.Core.csproj
+++ b/src/Artemis.Core/Artemis.Core.csproj
@@ -183,8 +183,8 @@
-
-
+
+
@@ -194,7 +194,7 @@
-
+
diff --git a/src/Artemis.Core/Events/ModuleEventArgs.cs b/src/Artemis.Core/Events/ModuleEventArgs.cs
deleted file mode 100644
index d2b6fa813..000000000
--- a/src/Artemis.Core/Events/ModuleEventArgs.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Artemis.Core.Plugins.Interfaces;
-
-namespace Artemis.Core.Events
-{
- public class ModuleEventArgs : System.EventArgs
- {
- public IPlugin Plugin { get; set; }
- }
-}
\ No newline at end of file
diff --git a/src/Artemis.Core/Events/PluginEventArgs.cs b/src/Artemis.Core/Events/PluginEventArgs.cs
new file mode 100644
index 000000000..a13e08df8
--- /dev/null
+++ b/src/Artemis.Core/Events/PluginEventArgs.cs
@@ -0,0 +1,10 @@
+using System;
+using Artemis.Plugins.Interfaces;
+
+namespace Artemis.Core.Events
+{
+ public class PluginEventArgs : EventArgs
+ {
+ public IPlugin Plugin { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Exceptions/ArtemisModuleException.cs b/src/Artemis.Core/Exceptions/ArtemisModuleException.cs
deleted file mode 100644
index a629d7126..000000000
--- a/src/Artemis.Core/Exceptions/ArtemisModuleException.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-using Artemis.Core.Models;
-
-namespace Artemis.Core.Exceptions
-{
- public class ArtemisModuleException : Exception
- {
- public ArtemisModuleException(ModuleInfo moduleInfo)
- {
- ModuleInfo = moduleInfo;
- }
-
- public ArtemisModuleException(ModuleInfo moduleInfo, string message) : base(message)
- {
- ModuleInfo = moduleInfo;
- }
-
- public ArtemisModuleException(ModuleInfo moduleInfo, string message, Exception inner) : base(message, inner)
- {
- ModuleInfo = moduleInfo;
- }
-
- public ModuleInfo ModuleInfo { get; }
- }
-}
\ No newline at end of file
diff --git a/src/Artemis.Core/Exceptions/ArtemisPluginException.cs b/src/Artemis.Core/Exceptions/ArtemisPluginException.cs
new file mode 100644
index 000000000..0282b0295
--- /dev/null
+++ b/src/Artemis.Core/Exceptions/ArtemisPluginException.cs
@@ -0,0 +1,25 @@
+using System;
+using Artemis.Core.Models;
+
+namespace Artemis.Core.Exceptions
+{
+ public class ArtemisPluginException : Exception
+ {
+ public ArtemisPluginException(PluginInfo pluginInfo)
+ {
+ PluginInfo = pluginInfo;
+ }
+
+ public ArtemisPluginException(PluginInfo pluginInfo, string message) : base(message)
+ {
+ PluginInfo = pluginInfo;
+ }
+
+ public ArtemisPluginException(PluginInfo pluginInfo, string message, Exception inner) : base(message, inner)
+ {
+ PluginInfo = pluginInfo;
+ }
+
+ public PluginInfo PluginInfo { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/ModuleInfo.cs b/src/Artemis.Core/Models/ModuleInfo.cs
deleted file mode 100644
index e47e98dfe..000000000
--- a/src/Artemis.Core/Models/ModuleInfo.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Collections.Generic;
-using Artemis.Core.Plugins.Interfaces;
-using Newtonsoft.Json;
-
-namespace Artemis.Core.Models
-{
- public class ModuleInfo
- {
- public string Name { get; set; }
- public string Version { get; set; }
- public string MainFile { get; set; }
- public IReadOnlyList SubFiles { get; set; }
-
- [JsonIgnore]
- public IPlugin Plugin { get; set; }
- }
-}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/PluginInfo.cs b/src/Artemis.Core/Models/PluginInfo.cs
new file mode 100644
index 000000000..1c8e2fa2b
--- /dev/null
+++ b/src/Artemis.Core/Models/PluginInfo.cs
@@ -0,0 +1,40 @@
+using Artemis.Plugins.Interfaces;
+using Newtonsoft.Json;
+
+namespace Artemis.Core.Models
+{
+ public class PluginInfo
+ {
+ ///
+ /// The name of the plugin
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// The version of the plugin
+ ///
+ public string Version { get; set; }
+
+ ///
+ /// The file implementing IPlugin, loaded on startup
+ ///
+ public string Main { get; set; }
+
+ ///
+ /// The file implementing IPluginViewModel, loaded when opened in the UI
+ ///
+ public string ViewModel { get; set; }
+
+ ///
+ /// The instantiated plugin, available after successful load
+ ///
+ [JsonIgnore]
+ public IPlugin Plugin { get; set; }
+
+ ///
+ /// Full path to the plugin's current folder
+ ///
+ [JsonIgnore]
+ public string Folder { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs
index ca61b1c68..434cb9ef4 100644
--- a/src/Artemis.Core/Services/CoreService.cs
+++ b/src/Artemis.Core/Services/CoreService.cs
@@ -22,7 +22,7 @@ namespace Artemis.Core.Services
private async Task Initialize()
{
- await _pluginService.LoadModules();
+ await _pluginService.LoadPlugins();
IsInitialized = true;
}
diff --git a/src/Artemis.Core/Services/Interfaces/IPluginService.cs b/src/Artemis.Core/Services/Interfaces/IPluginService.cs
index ea83d4050..f086b1513 100644
--- a/src/Artemis.Core/Services/Interfaces/IPluginService.cs
+++ b/src/Artemis.Core/Services/Interfaces/IPluginService.cs
@@ -1,16 +1,44 @@
using System;
+using System.Collections.ObjectModel;
using System.Threading.Tasks;
using Artemis.Core.Events;
+using Artemis.Core.Models;
using Artemis.Plugins.Interfaces;
namespace Artemis.Core.Services.Interfaces
{
public interface IPluginService : IArtemisService, IDisposable
{
- Task LoadModules();
- Task ReloadModule(IPlugin plugin);
+ bool LoadingPlugins { get; }
+ ReadOnlyCollection Plugins { get; }
- event EventHandler ModuleLoaded;
- event EventHandler ModuleReloaded;
+ ///
+ /// Loads all installed plugins. If plugins already loaded this will reload them all
+ ///
+ ///
+ Task LoadPlugins();
+
+ Task ReloadPlugin(PluginInfo pluginInfo);
+ Task GetPluginViewModel(PluginInfo pluginInfo);
+
+ ///
+ /// Occurs when a single plugin has loaded
+ ///
+ event EventHandler PluginLoaded;
+
+ ///
+ /// Occurs when a single plugin has reloaded
+ ///
+ event EventHandler PluginReloaded;
+
+ ///
+ /// Occurs when loading all plugins has started
+ ///
+ event EventHandler StartedLoadingPlugins;
+
+ ///
+ /// Occurs when loading all plugins has finished
+ ///
+ event EventHandler FinishedLoadedPlugins;
}
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/PluginService.cs b/src/Artemis.Core/Services/PluginService.cs
index 839dc12a9..475fbdace 100644
--- a/src/Artemis.Core/Services/PluginService.cs
+++ b/src/Artemis.Core/Services/PluginService.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
+using System.Linq;
using System.Threading.Tasks;
using Artemis.Core.Events;
using Artemis.Core.Exceptions;
@@ -10,109 +11,127 @@ using Artemis.Core.Services.Interfaces;
using Artemis.Plugins.Interfaces;
using CSScriptLibrary;
using Newtonsoft.Json;
+using Ninject;
namespace Artemis.Core.Services
{
public class PluginService : IPluginService
{
- private readonly List _modules;
+ private readonly IKernel _kernel;
+ private readonly List _plugins;
- public PluginService()
+ public PluginService(IKernel kernel)
{
- _modules = new List();
+ _kernel = kernel;
+ _plugins = new List();
- if (!Directory.Exists(Constants.DataFolder + "modules"))
- Directory.CreateDirectory(Constants.DataFolder + "modules");
+ if (!Directory.Exists(Constants.DataFolder + "plugins"))
+ Directory.CreateDirectory(Constants.DataFolder + "plugins");
}
- public bool LoadingModules { get; private set; }
- public ReadOnlyCollection Modules => _modules.AsReadOnly();
+ public bool LoadingPlugins { get; private set; }
+ public ReadOnlyCollection Plugins => _plugins.AsReadOnly();
///
- /// Loads all installed modules. If modules already loaded this will reload them all
+ /// Loads all installed plugins. If plugins already loaded this will reload them all
///
///
- public async Task LoadModules()
+ public async Task LoadPlugins()
{
- if (LoadingModules)
- throw new ArtemisCoreException("Cannot load modules while a previous load hasn't been completed yet.");
+ if (LoadingPlugins)
+ throw new ArtemisCoreException("Cannot load plugins while a previous load hasn't been completed yet.");
- OnStartedLoadingModules();
+ OnStartedLoadingPlugins();
- // Empty the list of modules
- _modules.Clear();
- // Iterate all module folders
- foreach (var directory in Directory.GetDirectories(Constants.DataFolder + "modules"))
- // Load each module
- _modules.Add(await LoadModuleFromFolder(directory));
+ // Empty the list of plugins
+ _plugins.Clear();
-
- OnFinishedLoadedModules();
+ // Iterate all plugin folders and load each plugin
+ foreach (var directory in Directory.GetDirectories(Constants.DataFolder + "plugins"))
+ _plugins.Add(await LoadPluginFromFolder(directory));
+
+ OnFinishedLoadedPlugins();
}
- public async Task ReloadModule(IPlugin plugin)
+ public async Task ReloadPlugin(PluginInfo pluginInfo)
{
}
+ public async Task GetPluginViewModel(PluginInfo pluginInfo)
+ {
+ // Compile the ViewModel and get the type
+ var compile = await Task.Run(() => CSScript.LoadFile(pluginInfo.Folder + pluginInfo.ViewModel));
+ var vmType = compile.ExportedTypes.FirstOrDefault(t => typeof(IPluginViewModel).IsAssignableFrom(t));
+ if (vmType == null)
+ throw new ArtemisPluginException(pluginInfo, "Cannot locate a view model for this plugin.");
+
+ // Instantiate the ViewModel with Ninject
+ return (IPluginViewModel) _kernel.Get(vmType);
+ }
+
public void Dispose()
{
}
- private async Task LoadModuleFromFolder(string folder)
+ private async Task LoadPluginFromFolder(string folder)
{
if (!folder.EndsWith("\\"))
folder += "\\";
- if (!File.Exists(folder + "module.json"))
- throw new ArtemisModuleException(null, "Failed to load module, no module.json found in " + folder);
+ if (!File.Exists(folder + "plugin.json"))
+ throw new ArtemisPluginException(null, "Failed to load plugin, no plugin.json found in " + folder);
- var moduleInfo = JsonConvert.DeserializeObject(File.ReadAllText(folder + "module.json"));
- // Load the main module which will contain a class implementing IModule
- var module = await CSScript.Evaluator.LoadFileAsync(folder + moduleInfo.MainFile);
- return module;
+ var pluginInfo = JsonConvert.DeserializeObject(File.ReadAllText(folder + "plugin.json"));
+ pluginInfo.Folder = folder;
+
+ // Load the main plugin which will contain a class implementing IPlugin
+ var plugin = await CSScript.Evaluator.LoadFileAsync(folder + pluginInfo.Main);
+ pluginInfo.Plugin = plugin;
+
+ return pluginInfo;
}
#region Events
///
- /// Occurs when a single module has loaded
+ /// Occurs when a single plugin has loaded
///
- public event EventHandler ModuleLoaded;
+ public event EventHandler PluginLoaded;
///
- /// Occurs when a single module has reloaded
+ /// Occurs when a single plugin has reloaded
///
- public event EventHandler ModuleReloaded;
+ public event EventHandler PluginReloaded;
///
- /// Occurs when loading all modules has started
+ /// Occurs when loading all plugins has started
///
- public event EventHandler StartedLoadingModules;
+ public event EventHandler StartedLoadingPlugins;
///
- /// Occurs when loading all modules has finished
+ /// Occurs when loading all plugins has finished
///
- public event EventHandler FinishedLoadedModules;
+ public event EventHandler FinishedLoadedPlugins;
- private void OnModuleLoaded(ModuleEventArgs e)
+ private void OnPluginLoaded(PluginEventArgs e)
{
- ModuleLoaded?.Invoke(this, e);
+ PluginLoaded?.Invoke(this, e);
}
- private void OnModuleReloaded(ModuleEventArgs e)
+ private void OnPluginReloaded(PluginEventArgs e)
{
- ModuleReloaded?.Invoke(this, e);
+ PluginReloaded?.Invoke(this, e);
}
- private void OnStartedLoadingModules()
+ private void OnStartedLoadingPlugins()
{
- LoadingModules = true;
- StartedLoadingModules?.Invoke(this, EventArgs.Empty);
+ LoadingPlugins = true;
+ StartedLoadingPlugins?.Invoke(this, EventArgs.Empty);
}
- private void OnFinishedLoadedModules()
+ private void OnFinishedLoadedPlugins()
{
- LoadingModules = false;
- FinishedLoadedModules?.Invoke(this, EventArgs.Empty);
+ LoadingPlugins = false;
+ FinishedLoadedPlugins?.Invoke(this, EventArgs.Empty);
}
#endregion
diff --git a/src/Artemis.Plugins/Artemis.Plugins.csproj b/src/Artemis.Plugins/Artemis.Plugins.csproj
index 4bc6760f5..1f0dbc33a 100644
--- a/src/Artemis.Plugins/Artemis.Plugins.csproj
+++ b/src/Artemis.Plugins/Artemis.Plugins.csproj
@@ -30,6 +30,9 @@
4
+
+ ..\packages\Ninject.3.3.4\lib\net45\Ninject.dll
+
..\packages\Stylet.1.1.21\lib\net45\Stylet.dll
diff --git a/src/Artemis.Plugins/Interfaces/IModule.cs b/src/Artemis.Plugins/Interfaces/IModule.cs
index 377ad9c6e..c666ecc8e 100644
--- a/src/Artemis.Plugins/Interfaces/IModule.cs
+++ b/src/Artemis.Plugins/Interfaces/IModule.cs
@@ -2,6 +2,5 @@
{
public interface IModule : IPlugin
{
- IPluginViewModel GetMainViewModel();
}
}
\ No newline at end of file
diff --git a/src/Artemis.Plugins/Interfaces/IPlugin.cs b/src/Artemis.Plugins/Interfaces/IPlugin.cs
index 8fdba572c..d9063dacc 100644
--- a/src/Artemis.Plugins/Interfaces/IPlugin.cs
+++ b/src/Artemis.Plugins/Interfaces/IPlugin.cs
@@ -1,6 +1,17 @@
-namespace Artemis.Plugins.Interfaces
+using System.Threading.Tasks;
+
+namespace Artemis.Plugins.Interfaces
{
public interface IPlugin
{
+ ///
+ /// Called when the plugin is loaded
+ ///
+ void LoadPlugin();
+
+ ///
+ /// Called when the plugin is unloaded
+ ///
+ void UnloadPlugin();
}
}
\ No newline at end of file
diff --git a/src/Artemis.Plugins/packages.config b/src/Artemis.Plugins/packages.config
index 0ef55cc6d..90d89f33c 100644
--- a/src/Artemis.Plugins/packages.config
+++ b/src/Artemis.Plugins/packages.config
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj
index 5c0d7cb28..8158fc1d2 100644
--- a/src/Artemis.UI/Artemis.UI.csproj
+++ b/src/Artemis.UI/Artemis.UI.csproj
@@ -151,6 +151,10 @@
{9b811f9b-86b9-4771-87af-72bae7078a36}
Artemis.Core
+
+ {cd23bc5e-57f0-46ce-a007-24d031146219}
+ Artemis.Plugins
+
{e489e5e3-1a65-4af5-a1ea-f9805fd19a65}
Artemis.Storage
diff --git a/src/Artemis.UI/ViewModels/HomeViewModel.cs b/src/Artemis.UI/ViewModels/HomeViewModel.cs
index 25d99189d..367ec1a12 100644
--- a/src/Artemis.UI/ViewModels/HomeViewModel.cs
+++ b/src/Artemis.UI/ViewModels/HomeViewModel.cs
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
+using Artemis.Core.Services.Interfaces;
using Artemis.UI.ViewModels.Interfaces;
using Stylet;
@@ -7,6 +8,15 @@ namespace Artemis.UI.ViewModels
{
public class HomeViewModel : Screen, IHomeViewModel
{
+ private readonly IPluginService _pluginService;
+
+ public HomeViewModel(IPluginService pluginService)
+ {
+ _pluginService = pluginService;
+
+ _pluginService.FinishedLoadedPlugins += PluginServiceOnFinishedLoadedPlugins;
+ }
+
public string Title => "Home";
public void OpenUrl(string url)
@@ -15,5 +25,15 @@ namespace Artemis.UI.ViewModels
if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
Process.Start(url);
}
+
+ ///
+ /// Populates the sidebar with plugins when they are finished loading
+ ///
+ ///
+ ///
+ private void PluginServiceOnFinishedLoadedPlugins(object sender, EventArgs eventArgs)
+ {
+ throw new NotImplementedException();
+ }
}
}
\ No newline at end of file