1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2026-01-01 10:13:30 +00:00

Plugins - Reworked most of the activation logic

This commit is contained in:
Robert 2020-11-10 20:51:29 +01:00
parent 1e0dc1894d
commit b56966c585
34 changed files with 509 additions and 362 deletions

View File

@ -8,11 +8,11 @@ namespace Artemis.Core
{ {
} }
public PluginEventArgs(PluginInfo pluginInfo) public PluginEventArgs(Plugin plugin)
{ {
PluginInfo = pluginInfo; Plugin = plugin;
} }
public PluginInfo PluginInfo { get; } public Plugin Plugin { get; }
} }
} }

View File

@ -0,0 +1,18 @@
using System;
namespace Artemis.Core
{
public class PluginImplementationEventArgs : EventArgs
{
public PluginImplementationEventArgs()
{
}
public PluginImplementationEventArgs(PluginImplementation pluginImplementation)
{
PluginImplementation = pluginImplementation;
}
public PluginImplementation PluginImplementation { get; }
}
}

View File

@ -4,19 +4,19 @@ namespace Artemis.Core
{ {
public class ArtemisPluginException : Exception public class ArtemisPluginException : Exception
{ {
public ArtemisPluginException(PluginInfo pluginInfo) public ArtemisPluginException(Plugin plugin)
{ {
PluginInfo = pluginInfo; Plugin = plugin;
} }
public ArtemisPluginException(PluginInfo pluginInfo, string message) : base(message) public ArtemisPluginException(Plugin plugin, string message) : base(message)
{ {
PluginInfo = pluginInfo; Plugin = plugin;
} }
public ArtemisPluginException(PluginInfo pluginInfo, string message, Exception inner) : base(message, inner) public ArtemisPluginException(Plugin plugin, string message, Exception inner) : base(message, inner)
{ {
PluginInfo = pluginInfo; Plugin = plugin;
} }
public ArtemisPluginException(string message) : base(message) public ArtemisPluginException(string message) : base(message)
@ -27,6 +27,6 @@ namespace Artemis.Core
{ {
} }
public PluginInfo PluginInfo { get; } public Plugin Plugin { get; }
} }
} }

View File

@ -10,12 +10,12 @@ namespace Artemis.Core.Ninject
{ {
private static readonly List<PluginSettings> PluginSettings = new List<PluginSettings>(); private static readonly List<PluginSettings> PluginSettings = new List<PluginSettings>();
private readonly IPluginRepository _pluginRepository; private readonly IPluginRepository _pluginRepository;
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
internal PluginSettingsProvider(IPluginRepository pluginRepository, IPluginService pluginService) internal PluginSettingsProvider(IPluginRepository pluginRepository, IPluginManagementService pluginManagementService)
{ {
_pluginRepository = pluginRepository; _pluginRepository = pluginRepository;
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
} }
protected override PluginSettings CreateInstance(IContext context) protected override PluginSettings CreateInstance(IContext context)
@ -27,7 +27,7 @@ namespace Artemis.Core.Ninject
// First try by PluginInfo parameter // First try by PluginInfo parameter
PluginInfo pluginInfo = parentRequest.Parameters.FirstOrDefault(p => p.Name == "PluginInfo")?.GetValue(context, null) as PluginInfo; PluginInfo pluginInfo = parentRequest.Parameters.FirstOrDefault(p => p.Name == "PluginInfo")?.GetValue(context, null) as PluginInfo;
if (pluginInfo == null) if (pluginInfo == null)
pluginInfo = _pluginService.GetPluginByAssembly(parentRequest.Service.Assembly)?.PluginInfo; pluginInfo = _pluginManagementService.GetPluginByAssembly(parentRequest.Service.Assembly)?.PluginInfo;
// Fall back to assembly based detection // Fall back to assembly based detection
if (pluginInfo == null) if (pluginInfo == null)
throw new ArtemisCoreException("PluginSettings can only be injected with the PluginInfo parameter provided " + throw new ArtemisCoreException("PluginSettings can only be injected with the PluginInfo parameter provided " +

View File

@ -1,18 +1,131 @@
namespace Artemis.Core using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using Artemis.Storage.Entities.Plugins;
using McMaster.NETCore.Plugins;
using Ninject;
using Stylet;
namespace Artemis.Core
{ {
/// <summary> /// <summary>
/// Represents a plugin /// Represents a plugin
/// </summary> /// </summary>
public abstract class Plugin public class Plugin : PropertyChangedBase, IDisposable
{ {
private readonly List<PluginImplementation> _implementations;
private bool _isEnabled;
internal Plugin(PluginInfo info, DirectoryInfo directory)
{
Info = info;
Directory = directory;
_implementations = new List<PluginImplementation>();
}
/// <summary>
/// Gets the plugin GUID
/// </summary>
public Guid Guid => Info.Guid;
/// <summary> /// <summary>
/// Gets the plugin info related to this plugin /// Gets the plugin info related to this plugin
/// </summary> /// </summary>
public PluginInfo Info { get; internal set; } public PluginInfo Info { get; }
/// <summary>
/// The plugins root directory
/// </summary>
public DirectoryInfo Directory { get; }
/// <summary> /// <summary>
/// Gets or sets a configuration dialog for this plugin that is accessible in the UI under Settings > Plugins /// Gets or sets a configuration dialog for this plugin that is accessible in the UI under Settings > Plugins
/// </summary> /// </summary>
public PluginConfigurationDialog ConfigurationDialog { get; protected set; } public PluginConfigurationDialog? ConfigurationDialog { get; protected set; }
/// <summary>
/// Indicates whether the user enabled the plugin or not
/// </summary>
public bool IsEnabled
{
get => _isEnabled;
private set => SetAndNotify(ref _isEnabled, value);
}
/// <summary>
/// Gets a read-only collection of all implementations this plugin provides
/// </summary>
public ReadOnlyCollection<PluginImplementation> Implementations => _implementations.AsReadOnly();
/// <summary>
/// The assembly the plugin code lives in
/// </summary>
internal Assembly? Assembly { get; set; }
/// <summary>
/// The Ninject kernel of the plugin
/// </summary>
internal IKernel? Kernel { get; set; }
/// <summary>
/// The PluginLoader backing this plugin
/// </summary>
internal PluginLoader? PluginLoader { get; set; }
/// <summary>
/// The entity representing the plugin
/// </summary>
internal PluginEntity? Entity { get; set; }
/// <summary>
/// Resolves the relative path provided in the <paramref name="path" /> parameter to an absolute path
/// </summary>
/// <param name="path">The path to resolve</param>
/// <returns>An absolute path pointing to the provided relative path</returns>
public string? ResolveRelativePath(string path)
{
return path == null ? null : Path.Combine(Directory.FullName, path);
}
internal void ApplyToEntity()
{
Entity.Id = Guid;
Entity.IsEnabled = IsEnabled;
}
internal void AddImplementation(PluginImplementation implementation)
{
implementation.Plugin = this;
_implementations.Add(implementation);
}
public void SetEnabled(bool enable)
{
if (IsEnabled == enable)
return;
if (!enable && Implementations.Any(e => e.IsEnabled))
throw new ArtemisCoreException("Cannot disable this plugin because it still has enabled implementations");
}
/// <inheritdoc />
public override string ToString()
{
return Info.ToString();
}
public void Dispose()
{
foreach (PluginImplementation pluginImplementation in Implementations)
pluginImplementation.Dispose();
Kernel?.Dispose();
PluginLoader?.Dispose();
}
} }
} }

View File

@ -1,27 +1,44 @@
using System; using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Artemis.Storage.Entities.Plugins;
using Stylet;
namespace Artemis.Core namespace Artemis.Core
{ {
/// <summary> /// <summary>
/// Represents an implementation of a certain type provided by a plugin /// Represents an implementation of a certain type provided by a plugin
/// </summary> /// </summary>
public abstract class PluginImplementation : IDisposable public abstract class PluginImplementation : PropertyChangedBase, IDisposable
{ {
private Exception? _loadException;
private bool _isEnabled;
/// <summary> /// <summary>
/// Gets the plugin that provides this implementation /// Gets the plugin that provides this implementation
/// </summary> /// </summary>
public Plugin Plugin { get; internal set; } public Plugin? Plugin { get; internal set; }
/// <summary>
/// Gets the plugin info related to this plugin
/// </summary>
public PluginInfo PluginInfo { get; internal set; }
/// <summary> /// <summary>
/// Gets whether the plugin is enabled /// Gets whether the plugin is enabled
/// </summary> /// </summary>
public bool IsEnabled { get; internal set; } public bool IsEnabled
{
get => _isEnabled;
internal set => SetAndNotify(ref _isEnabled, value);
}
/// <summary>
/// Gets the exception thrown while loading
/// </summary>
public Exception? LoadException
{
get => _loadException;
internal set => SetAndNotify(ref _loadException, value);
}
internal PluginImplementationEntity? Entity { get; set; }
/// <summary> /// <summary>
/// Called when the implementation is activated /// Called when the implementation is activated
@ -35,62 +52,75 @@ namespace Artemis.Core
internal void SetEnabled(bool enable, bool isAutoEnable = false) internal void SetEnabled(bool enable, bool isAutoEnable = false)
{ {
if (enable && !IsEnabled) if (enable == IsEnabled)
return;
if (Plugin == null)
throw new ArtemisCoreException("Cannot enable a plugin implementation that is not associated with a plugin");
lock (Plugin)
{ {
if (!Plugin.IsEnabled)
throw new ArtemisCoreException("Cannot enable a plugin implementation of a disabled plugin");
if (!enable)
{
IsEnabled = false;
// Even if disable failed, still leave it in a disabled state to avoid more issues
InternalDisable();
OnDisabled();
return;
}
try try
{ {
if (isAutoEnable && PluginInfo.GetLockFileCreated()) if (isAutoEnable && GetLockFileCreated())
{ {
// Don't wrap existing lock exceptions, simply rethrow them // Don't wrap existing lock exceptions, simply rethrow them
if (PluginInfo.LoadException is ArtemisPluginLockException) if (LoadException is ArtemisPluginLockException)
throw PluginInfo.LoadException; throw LoadException;
throw new ArtemisPluginLockException(PluginInfo.LoadException); throw new ArtemisPluginLockException(LoadException);
} }
IsEnabled = true; IsEnabled = true;
PluginInfo.IsEnabled = true; CreateLockFile();
PluginInfo.CreateLockFile();
// Allow up to 15 seconds for plugins to activate. // Allow up to 15 seconds for plugins to activate.
// This means plugins that need more time should do their long running tasks in a background thread, which is intentional // This means plugins that need more time should do their long running tasks in a background thread, which is intentional
// Little meh: Running this from a different thread could cause deadlocks ManualResetEvent wait = new ManualResetEvent(false);
Task enableTask = Task.Run(InternalEnable); Thread work = new Thread(() =>
if (!enableTask.Wait(TimeSpan.FromSeconds(15))) {
throw new ArtemisPluginException(PluginInfo, "Plugin load timeout"); InternalEnable();
wait.Set();
});
work.Start();
wait.WaitOne(TimeSpan.FromSeconds(15));
if (work.IsAlive)
{
work.Abort();
throw new ArtemisPluginException(Plugin, "Plugin load timeout");
}
PluginInfo.LoadException = null; LoadException = null;
OnEnabled(); OnEnabled();
} }
// If enable failed, put it back in a disabled state // If enable failed, put it back in a disabled state
catch (Exception e) catch (Exception e)
{ {
IsEnabled = false; IsEnabled = false;
PluginInfo.IsEnabled = false; LoadException = e;
PluginInfo.LoadException = e;
throw; throw;
} }
finally finally
{ {
if (!(PluginInfo.LoadException is ArtemisPluginLockException)) // Clean up the lock file unless the failure was due to the lock file
PluginInfo.DeleteLockFile(); // After all, we failed but not miserably :)
if (!(LoadException is ArtemisPluginLockException))
DeleteLockFile();
} }
} }
else if (!enable && IsEnabled)
{
IsEnabled = false;
PluginInfo.IsEnabled = false;
// Even if disable failed, still leave it in a disabled state to avoid more issues
InternalDisable();
OnDisabled();
}
// A failed load is still enabled in plugin info (to avoid disabling it permanently after a fail)
// update even that when manually disabling
else if (!enable && !IsEnabled)
{
PluginInfo.IsEnabled = false;
}
} }
internal virtual void InternalEnable() internal virtual void InternalEnable()
@ -109,6 +139,35 @@ namespace Artemis.Core
Disable(); Disable();
} }
#region Loading
internal void CreateLockFile()
{
if (Plugin == null)
throw new ArtemisCoreException("Cannot lock a plugin implementation that is not associated with a plugin");
File.Create(Plugin.ResolveRelativePath($"{GetType().FullName}.lock")).Close();
}
internal void DeleteLockFile()
{
if (Plugin == null)
throw new ArtemisCoreException("Cannot lock a plugin implementation that is not associated with a plugin");
if (GetLockFileCreated())
File.Delete(Plugin.ResolveRelativePath($"{GetType().FullName}.lock"));
}
internal bool GetLockFileCreated()
{
if (Plugin == null)
throw new ArtemisCoreException("Cannot lock a plugin implementation that is not associated with a plugin");
return File.Exists(Plugin.ResolveRelativePath($"{GetType().FullName}.lock"));
}
#endregion
#region Events #region Events
/// <summary> /// <summary>

View File

@ -1,10 +1,5 @@
using System; using System;
using System.IO;
using System.Reflection;
using Artemis.Storage.Entities.Plugins;
using McMaster.NETCore.Plugins;
using Newtonsoft.Json; using Newtonsoft.Json;
using Ninject;
using Stylet; using Stylet;
namespace Artemis.Core namespace Artemis.Core
@ -16,14 +11,11 @@ namespace Artemis.Core
public class PluginInfo : PropertyChangedBase public class PluginInfo : PropertyChangedBase
{ {
private string _description; private string _description;
private DirectoryInfo _directory;
private Guid _guid; private Guid _guid;
private string _icon; private string _icon;
private Plugin _instance;
private bool _isEnabled;
private Exception _loadException;
private string _main; private string _main;
private string _name; private string _name;
private Plugin _plugin;
private Version _version; private Version _version;
internal PluginInfo() internal PluginInfo()
@ -92,93 +84,19 @@ namespace Artemis.Core
internal set => SetAndNotify(ref _main, value); internal set => SetAndNotify(ref _main, value);
} }
/// <summary>
/// The plugins root directory
/// </summary>
public DirectoryInfo Directory
{
get => _directory;
internal set => SetAndNotify(ref _directory, value);
}
/// <summary> /// <summary>
/// Gets the plugin this info is associated with /// Gets the plugin this info is associated with
/// </summary> /// </summary>
public Plugin Instance public Plugin Plugin
{ {
get => _instance; get => _plugin;
internal set => SetAndNotify(ref _instance, value); internal set => SetAndNotify(ref _plugin, value);
} }
/// <summary>
/// Indicates whether the user enabled the plugin or not
/// </summary>
public bool IsEnabled
{
get => _isEnabled;
internal set => SetAndNotify(ref _isEnabled, value);
}
/// <summary>
/// Gets the exception thrown while loading
/// </summary>
public Exception LoadException
{
get => _loadException;
internal set => SetAndNotify(ref _loadException, value);
}
/// <summary>
/// The assembly the plugin code lives in
/// </summary>
public Assembly Assembly { get; internal set; }
/// <summary>
/// The Ninject kernel of the plugin
/// </summary>
public IKernel Kernel { get; internal set; }
/// <summary>
/// The PluginLoader backing this plugin
/// </summary>
internal PluginLoader PluginLoader { get; set; }
/// <summary>
/// The entity representing the plugin
/// </summary>
internal PluginEntity PluginEntity { get; set; }
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
return $"{Name} v{Version} - {Guid}"; return $"{Name} v{Version} - {Guid}";
} }
public string? ResolveRelativePath(string path)
{
return path == null ? null : Path.Combine(Directory.FullName, path);
}
internal void ApplyToEntity()
{
PluginEntity.Id = Guid;
PluginEntity.IsEnabled = IsEnabled;
}
internal void CreateLockFile()
{
File.Create(Path.Combine(Directory.FullName, "artemis.lock")).Close();
}
internal void DeleteLockFile()
{
if (GetLockFileCreated())
File.Delete(Path.Combine(Directory.FullName, "artemis.lock"));
}
internal bool GetLockFileCreated()
{
return File.Exists(Path.Combine(Directory.FullName, "artemis.lock"));
}
} }
} }

View File

@ -19,9 +19,9 @@ namespace Artemis.Core
Interval = interval; Interval = interval;
Action = action; Action = action;
PluginInfo.Instance.Enabled += InstanceOnEnabled; PluginInfo.Plugin.Enabled += InstanceOnEnabled;
PluginInfo.Instance.Disabled += InstanceOnDisabled; PluginInfo.Plugin.Disabled += InstanceOnDisabled;
if (PluginInfo.Instance.IsEnabled) if (PluginInfo.Plugin.IsEnabled)
Start(); Start();
} }
@ -31,9 +31,9 @@ namespace Artemis.Core
Interval = interval; Interval = interval;
AsyncAction = asyncAction; AsyncAction = asyncAction;
PluginInfo.Instance.Enabled += InstanceOnEnabled; PluginInfo.Plugin.Enabled += InstanceOnEnabled;
PluginInfo.Instance.Disabled += InstanceOnDisabled; PluginInfo.Plugin.Disabled += InstanceOnDisabled;
if (PluginInfo.Instance.IsEnabled) if (PluginInfo.Plugin.IsEnabled)
Start(); Start();
} }
@ -66,7 +66,7 @@ namespace Artemis.Core
{ {
lock (this) lock (this)
{ {
if (!PluginInfo.Instance.IsEnabled) if (!PluginInfo.Plugin.IsEnabled)
throw new ArtemisPluginException("Cannot start a timed update for a disabled plugin"); throw new ArtemisPluginException("Cannot start a timed update for a disabled plugin");
if (_timer != null) if (_timer != null)
@ -99,7 +99,7 @@ namespace Artemis.Core
private void TimerOnElapsed(object sender, ElapsedEventArgs e) private void TimerOnElapsed(object sender, ElapsedEventArgs e)
{ {
if (!PluginInfo.Instance.IsEnabled) if (!PluginInfo.Plugin.IsEnabled)
return; return;
lock (this) lock (this)
@ -108,7 +108,7 @@ namespace Artemis.Core
_lastEvent = DateTime.Now; _lastEvent = DateTime.Now;
// Modules don't always want to update, honor that // Modules don't always want to update, honor that
if (PluginInfo.Instance is Module module && !module.IsUpdateAllowed) if (PluginInfo.Plugin is Module module && !module.IsUpdateAllowed)
return; return;
if (Action != null) if (Action != null)

View File

@ -28,7 +28,7 @@ namespace Artemis.Core.Services
private readonly Stopwatch _frameStopWatch; private readonly Stopwatch _frameStopWatch;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly PluginSetting<LogEventLevel> _loggingLevel; private readonly PluginSetting<LogEventLevel> _loggingLevel;
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
private readonly IProfileService _profileService; private readonly IProfileService _profileService;
private readonly IRgbService _rgbService; private readonly IRgbService _rgbService;
private readonly ISurfaceService _surfaceService; private readonly ISurfaceService _surfaceService;
@ -36,14 +36,14 @@ namespace Artemis.Core.Services
private List<Module> _modules; private List<Module> _modules;
// ReSharper disable once UnusedParameter.Local - Storage migration service is injected early to ensure it runs before anything else // ReSharper disable once UnusedParameter.Local - Storage migration service is injected early to ensure it runs before anything else
public CoreService(IKernel kernel, ILogger logger, StorageMigrationService _, ISettingsService settingsService, IPluginService pluginService, public CoreService(IKernel kernel, ILogger logger, StorageMigrationService _, ISettingsService settingsService, IPluginManagementService pluginManagementService,
IRgbService rgbService, ISurfaceService surfaceService, IProfileService profileService, IModuleService moduleService) IRgbService rgbService, ISurfaceService surfaceService, IProfileService profileService, IModuleService moduleService)
{ {
Kernel = kernel; Kernel = kernel;
Constants.CorePluginInfo.Kernel = kernel; Constants.CorePluginInfo.Kernel = kernel;
_logger = logger; _logger = logger;
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
_rgbService = rgbService; _rgbService = rgbService;
_surfaceService = surfaceService; _surfaceService = surfaceService;
_profileService = profileService; _profileService = profileService;
@ -57,8 +57,8 @@ namespace Artemis.Core.Services
_rgbService.Surface.Updated += SurfaceOnUpdated; _rgbService.Surface.Updated += SurfaceOnUpdated;
_loggingLevel.SettingChanged += (sender, args) => ApplyLoggingLevel(); _loggingLevel.SettingChanged += (sender, args) => ApplyLoggingLevel();
_pluginService.PluginEnabled += (sender, args) => UpdatePluginCache(); _pluginManagementService.PluginEnabled += (sender, args) => UpdatePluginCache();
_pluginService.PluginDisabled += (sender, args) => UpdatePluginCache(); _pluginManagementService.PluginDisabled += (sender, args) => UpdatePluginCache();
} }
public TimeSpan FrameTime { get; private set; } public TimeSpan FrameTime { get; private set; }
@ -68,7 +68,7 @@ namespace Artemis.Core.Services
public void Dispose() public void Dispose()
{ {
// Dispose services // Dispose services
_pluginService.Dispose(); _pluginManagementService.Dispose();
} }
public bool IsInitialized { get; set; } public bool IsInitialized { get; set; }
@ -85,8 +85,8 @@ namespace Artemis.Core.Services
DeserializationLogger.Initialize(Kernel); DeserializationLogger.Initialize(Kernel);
// Initialize the services // Initialize the services
_pluginService.CopyBuiltInPlugins(); _pluginManagementService.CopyBuiltInPlugins();
_pluginService.LoadPlugins(StartupArguments.Contains("--ignore-plugin-lock")); _pluginManagementService.LoadPlugins(StartupArguments.Contains("--ignore-plugin-lock"));
ArtemisSurface surfaceConfig = _surfaceService.ActiveSurface; ArtemisSurface surfaceConfig = _surfaceService.ActiveSurface;
if (surfaceConfig != null) if (surfaceConfig != null)
@ -133,8 +133,8 @@ namespace Artemis.Core.Services
private void UpdatePluginCache() private void UpdatePluginCache()
{ {
_modules = _pluginService.GetPluginsOfType<Module>().Where(p => p.IsEnabled).ToList(); _modules = _pluginManagementService.GetPluginsOfType<Module>().Where(p => p.IsEnabled).ToList();
_dataModelExpansions = _pluginService.GetPluginsOfType<BaseDataModelExpansion>().Where(p => p.IsEnabled).ToList(); _dataModelExpansions = _pluginManagementService.GetPluginsOfType<BaseDataModelExpansion>().Where(p => p.IsEnabled).ToList();
} }
private void ConfigureJsonConvert() private void ConfigureJsonConvert()

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Reflection; using System.Reflection;
using RGB.NET.Core; using RGB.NET.Core;
@ -8,7 +9,7 @@ namespace Artemis.Core.Services
/// <summary> /// <summary>
/// A service providing plugin management /// A service providing plugin management
/// </summary> /// </summary>
public interface IPluginService : IArtemisService, IDisposable public interface IPluginManagementService : IArtemisService, IDisposable
{ {
/// <summary> /// <summary>
/// Indicates whether or not plugins are currently being loaded /// Indicates whether or not plugins are currently being loaded
@ -35,7 +36,7 @@ namespace Artemis.Core.Services
/// Loads the plugin defined in the provided <see cref="PluginInfo" /> /// Loads the plugin defined in the provided <see cref="PluginInfo" />
/// </summary> /// </summary>
/// <param name="pluginInfo">The plugin info defining the plugin to load</param> /// <param name="pluginInfo">The plugin info defining the plugin to load</param>
void LoadPlugin(PluginInfo pluginInfo); void LoadPlugin(DirectoryInfo pluginInfo);
/// <summary> /// <summary>
/// Unloads the plugin defined in the provided <see cref="PluginInfo" /> /// Unloads the plugin defined in the provided <see cref="PluginInfo" />
@ -48,13 +49,13 @@ namespace Artemis.Core.Services
/// </summary> /// </summary>
/// <param name="pluginImplementation"></param> /// <param name="pluginImplementation"></param>
/// <param name="isAutoEnable">If true, fails if there is a lock file present</param> /// <param name="isAutoEnable">If true, fails if there is a lock file present</param>
void EnablePlugin(PluginImplementation pluginImplementation, bool isAutoEnable = false); void EnablePluginImplementation(PluginImplementation pluginImplementation, bool isAutoEnable = false);
/// <summary> /// <summary>
/// Disables the provided plugin /// Disables the provided plugin
/// </summary> /// </summary>
/// <param name="pluginImplementation"></param> /// <param name="pluginImplementation"></param>
void DisablePlugin(PluginImplementation pluginImplementation); void DisablePluginImplementation(PluginImplementation pluginImplementation);
/// <summary> /// <summary>
/// Finds the plugin info related to the plugin /// Finds the plugin info related to the plugin

View File

@ -17,22 +17,22 @@ namespace Artemis.Core.Services
private static readonly SemaphoreSlim ActiveModuleSemaphore = new SemaphoreSlim(1, 1); private static readonly SemaphoreSlim ActiveModuleSemaphore = new SemaphoreSlim(1, 1);
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IModuleRepository _moduleRepository; private readonly IModuleRepository _moduleRepository;
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
private readonly IProfileService _profileService; private readonly IProfileService _profileService;
public ModuleService(ILogger logger, IModuleRepository moduleRepository, IPluginService pluginService, IProfileService profileService) public ModuleService(ILogger logger, IModuleRepository moduleRepository, IPluginManagementService pluginManagementService, IProfileService profileService)
{ {
_logger = logger; _logger = logger;
_moduleRepository = moduleRepository; _moduleRepository = moduleRepository;
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
_profileService = profileService; _profileService = profileService;
_pluginService.PluginEnabled += PluginServiceOnPluginEnabled; _pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementEnabled;
Timer activationUpdateTimer = new Timer(2000); Timer activationUpdateTimer = new Timer(2000);
activationUpdateTimer.Start(); activationUpdateTimer.Start();
activationUpdateTimer.Elapsed += ActivationUpdateTimerOnElapsed; activationUpdateTimer.Elapsed += ActivationUpdateTimerOnElapsed;
foreach (Module module in _pluginService.GetPluginsOfType<Module>()) foreach (Module module in _pluginManagementService.GetPluginsOfType<Module>())
InitialiseOrApplyPriority(module); InitialiseOrApplyPriority(module);
} }
@ -56,7 +56,7 @@ namespace Artemis.Core.Services
_logger.Information("Clearing active module override"); _logger.Information("Clearing active module override");
// Always deactivate all other modules whenever override is called // Always deactivate all other modules whenever override is called
List<Module> modules = _pluginService.GetPluginsOfType<Module>().ToList(); List<Module> modules = _pluginManagementService.GetPluginsOfType<Module>().ToList();
foreach (Module module in modules.Where(m => m != overrideModule)) foreach (Module module in modules.Where(m => m != overrideModule))
OverrideDeactivate(module, overrideModule != null); OverrideDeactivate(module, overrideModule != null);
@ -97,7 +97,7 @@ namespace Artemis.Core.Services
Stopwatch stopwatch = new Stopwatch(); Stopwatch stopwatch = new Stopwatch();
stopwatch.Start(); stopwatch.Start();
List<Module> modules = _pluginService.GetPluginsOfType<Module>().ToList(); List<Module> modules = _pluginManagementService.GetPluginsOfType<Module>().ToList();
List<Task> tasks = new List<Task>(); List<Task> tasks = new List<Task>();
foreach (Module module in modules) foreach (Module module in modules)
{ {
@ -128,7 +128,7 @@ namespace Artemis.Core.Services
if (module.PriorityCategory == category && module.Priority == priority) if (module.PriorityCategory == category && module.Priority == priority)
return; return;
List<Module> modules = _pluginService.GetPluginsOfType<Module>().Where(m => m.PriorityCategory == category).OrderBy(m => m.Priority).ToList(); List<Module> modules = _pluginManagementService.GetPluginsOfType<Module>().Where(m => m.PriorityCategory == category).OrderBy(m => m.Priority).ToList();
if (modules.Contains(module)) if (modules.Contains(module))
modules.Remove(module); modules.Remove(module);
@ -234,9 +234,9 @@ namespace Artemis.Core.Services
} }
} }
private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e) private void PluginManagementServiceOnPluginManagementEnabled(object sender, PluginEventArgs e)
{ {
if (e.PluginInfo.Instance is Module module) if (e.PluginInfo.Plugin is Module module)
InitialiseOrApplyPriority(module); InitialiseOrApplyPriority(module);
} }

View File

@ -22,19 +22,19 @@ namespace Artemis.Core.Services
/// <summary> /// <summary>
/// Provides access to plugin loading and unloading /// Provides access to plugin loading and unloading
/// </summary> /// </summary>
internal class PluginService : IPluginService internal class PluginManagementService : IPluginManagementService
{ {
private readonly IKernel _kernel; private readonly IKernel _kernel;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IPluginRepository _pluginRepository; private readonly IPluginRepository _pluginRepository;
private readonly List<PluginInfo> _plugins; private readonly List<Plugin> _plugins;
public PluginService(IKernel kernel, ILogger logger, IPluginRepository pluginRepository) public PluginManagementService(IKernel kernel, ILogger logger, IPluginRepository pluginRepository)
{ {
_kernel = kernel; _kernel = kernel;
_logger = logger; _logger = logger;
_pluginRepository = pluginRepository; _pluginRepository = pluginRepository;
_plugins = new List<PluginInfo>(); _plugins = new List<Plugin>();
// Ensure the plugins directory exists // Ensure the plugins directory exists
if (!Directory.Exists(Constants.DataFolder + "plugins")) if (!Directory.Exists(Constants.DataFolder + "plugins"))
@ -43,6 +43,8 @@ namespace Artemis.Core.Services
public bool LoadingPlugins { get; private set; } public bool LoadingPlugins { get; private set; }
#region Built in plugins
public void CopyBuiltInPlugins() public void CopyBuiltInPlugins()
{ {
OnCopyingBuildInPlugins(); OnCopyingBuildInPlugins();
@ -101,6 +103,10 @@ namespace Artemis.Core.Services
} }
} }
#endregion
#region Plugins
public void LoadPlugins(bool ignorePluginLock) public void LoadPlugins(bool ignorePluginLock)
{ {
if (LoadingPlugins) if (LoadingPlugins)
@ -119,15 +125,7 @@ namespace Artemis.Core.Services
{ {
try try
{ {
// Load the metadata LoadPlugin(subDirectory);
string metadataFile = Path.Combine(subDirectory.FullName, "plugin.json");
if (!File.Exists(metadataFile)) _logger.Warning(new ArtemisPluginException("Couldn't find the plugins metadata file at " + metadataFile), "Plugin exception");
// Locate the main entry
PluginInfo pluginInfo = JsonConvert.DeserializeObject<PluginInfo>(File.ReadAllText(metadataFile));
pluginInfo.Directory = subDirectory;
LoadPlugin(pluginInfo);
} }
catch (Exception e) catch (Exception e)
{ {
@ -136,15 +134,18 @@ namespace Artemis.Core.Services
} }
// Activate plugins after they are all loaded // Activate plugins after they are all loaded
foreach (PluginInfo pluginInfo in _plugins.Where(p => p.IsEnabled)) foreach (Plugin plugin in _plugins.Where(p => p.Entity.IsEnabled))
{ {
try foreach (PluginImplementation pluginImplementation in plugin.Implementations.Where(i => i.Entity.IsEnabled))
{ {
EnablePlugin(pluginInfo.Instance, !ignorePluginLock); try
} {
catch (Exception) EnablePluginImplementation(pluginImplementation, !ignorePluginLock);
{ }
// ignored, logged in EnablePlugin catch (Exception)
{
// ignored, logged in EnablePlugin
}
} }
} }
@ -164,30 +165,37 @@ namespace Artemis.Core.Services
} }
} }
public void LoadPlugin(PluginInfo pluginInfo) public void LoadPlugin(DirectoryInfo pluginDirectory)
{ {
lock (_plugins) lock (_plugins)
{ {
_logger.Debug("Loading plugin {pluginInfo}", pluginInfo); _logger.Debug("Loading plugin from {directory}", pluginDirectory.FullName);
OnPluginLoading(new PluginEventArgs(pluginInfo));
// Unload the plugin first if it is already loaded // Load the metadata
if (_plugins.Contains(pluginInfo)) string metadataFile = Path.Combine(pluginDirectory.FullName, "plugin.json");
UnloadPlugin(pluginInfo); if (!File.Exists(metadataFile))
_logger.Warning(new ArtemisPluginException("Couldn't find the plugins metadata file at " + metadataFile), "Plugin exception");
PluginEntity pluginEntity = _pluginRepository.GetPluginByGuid(pluginInfo.Guid); // PluginInfo contains the ID which we need to move on
if (pluginEntity == null) PluginInfo pluginInfo = JsonConvert.DeserializeObject<PluginInfo>(File.ReadAllText(metadataFile));
pluginEntity = new PluginEntity {Id = pluginInfo.Guid, IsEnabled = true};
pluginInfo.PluginEntity = pluginEntity; // Ensure the plugin is not already loaded
pluginInfo.IsEnabled = pluginEntity.IsEnabled; if (_plugins.Any(p => p.Guid == pluginInfo.Guid))
throw new ArtemisCoreException("Cannot load a plugin that is already loaded");
string mainFile = Path.Combine(pluginInfo.Directory.FullName, pluginInfo.Main); Plugin plugin = new Plugin(pluginInfo, pluginDirectory);
OnPluginLoading(new PluginEventArgs(plugin));
// Load the entity and fall back on creating a new one
plugin.Entity = _pluginRepository.GetPluginByGuid(pluginInfo.Guid) ?? new PluginEntity { Id = plugin.Guid, IsEnabled = true };
// Locate the main assembly entry
string? mainFile = plugin.ResolveRelativePath(plugin.Info.Main);
if (!File.Exists(mainFile)) if (!File.Exists(mainFile))
throw new ArtemisPluginException(pluginInfo, "Couldn't find the plugins main entry at " + mainFile); throw new ArtemisPluginException(plugin, "Couldn't find the plugins main entry at " + mainFile);
// Load the plugin, all types implementing Plugin and register them with DI // Load the plugin, all types implementing Plugin and register them with DI
pluginInfo.PluginLoader = PluginLoader.CreateFromAssemblyFile(mainFile, configure => plugin.PluginLoader = PluginLoader.CreateFromAssemblyFile(mainFile!, configure =>
{ {
configure.IsUnloadable = true; configure.IsUnloadable = true;
configure.PreferSharedTypes = true; configure.PreferSharedTypes = true;
@ -195,57 +203,58 @@ namespace Artemis.Core.Services
try try
{ {
pluginInfo.Assembly = pluginInfo.PluginLoader.LoadDefaultAssembly(); plugin.Assembly = plugin.PluginLoader.LoadDefaultAssembly();
} }
catch (Exception e) catch (Exception e)
{ {
throw new ArtemisPluginException(pluginInfo, "Failed to load the plugins assembly", e); throw new ArtemisPluginException(plugin, "Failed to load the plugins assembly", e);
} }
// Get the Plugin implementation from the main assembly and if there is only one, instantiate it // Get the Plugin implementation from the main assembly and if there is only one, instantiate it
List<Type> pluginTypes; List<Type> implementationTypes;
try try
{ {
pluginTypes = pluginInfo.Assembly.GetTypes().Where(t => typeof(PluginImplementation).IsAssignableFrom(t)).ToList(); implementationTypes = plugin.Assembly.GetTypes().Where(t => typeof(PluginImplementation).IsAssignableFrom(t)).ToList();
} }
catch (ReflectionTypeLoadException e) catch (ReflectionTypeLoadException e)
{ {
throw new ArtemisPluginException(pluginInfo, "Failed to initialize the plugin assembly", new AggregateException(e.LoaderExceptions)); throw new ArtemisPluginException(plugin, "Failed to initialize the plugin assembly", new AggregateException(e.LoaderExceptions));
} }
if (pluginTypes.Count > 1) // Create the Ninject child kernel and load the module
throw new ArtemisPluginException(pluginInfo, $"Plugin contains {pluginTypes.Count} implementations of Plugin, only 1 allowed"); plugin.Kernel = new ChildKernel(_kernel);
if (pluginTypes.Count == 0) plugin.Kernel.Load(new PluginModule(pluginInfo));
throw new ArtemisPluginException(pluginInfo, "Plugin contains no implementation of Plugin");
Type pluginType = pluginTypes.Single(); if (!implementationTypes.Any())
try _logger.Warning("Plugin {plugin} contains no implementations", plugin);
// Create instances of each implementation and add them to the plugin
// Construction should be simple and not contain any logic so failure at this point means the entire plugin fails
foreach (Type implementationType in implementationTypes)
{ {
IParameter[] parameters = { try
new Parameter("PluginInfo", pluginInfo, false) {
}; PluginImplementation instance = (PluginImplementation)plugin.Kernel.Get(implementationType);
pluginInfo.Kernel = new ChildKernel(_kernel); plugin.AddImplementation(instance);
pluginInfo.Kernel.Load(new PluginModule(pluginInfo)); }
pluginInfo.Instance = (PluginImplementation) pluginInfo.Kernel.Get(pluginType, constraint: null, parameters: parameters); catch (Exception e)
pluginInfo.Instance.PluginInfo = pluginInfo; {
} throw new ArtemisPluginException(plugin, "Failed to load instantiate implementation", e);
catch (Exception e) }
{
throw new ArtemisPluginException(pluginInfo, "Failed to instantiate the plugin", e);
} }
_plugins.Add(pluginInfo); _plugins.Add(plugin);
OnPluginLoaded(new PluginEventArgs(pluginInfo)); OnPluginLoaded(new PluginEventArgs(plugin));
} }
} }
public void UnloadPlugin(PluginInfo pluginInfo) public void UnloadPlugin(Plugin plugin)
{ {
lock (_plugins) lock (_plugins)
{ {
try try
{ {
pluginInfo.Instance.SetEnabled(false); plugin.SetEnabled(false);
} }
catch (Exception) catch (Exception)
{ {
@ -253,23 +262,24 @@ namespace Artemis.Core.Services
} }
finally finally
{ {
OnPluginDisabled(new PluginEventArgs(pluginInfo)); OnPluginDisabled(new PluginEventArgs(plugin));
} }
pluginInfo.Instance.Dispose(); plugin.Dispose();
pluginInfo.PluginLoader.Dispose(); _plugins.Remove(plugin);
pluginInfo.Kernel.Dispose();
_plugins.Remove(pluginInfo); OnPluginUnloaded(new PluginEventArgs(plugin));
OnPluginUnloaded(new PluginEventArgs(pluginInfo));
} }
} }
public void EnablePlugin(PluginImplementation pluginImplementation, bool isAutoEnable = false) #endregion
#region Implementations
public void EnablePluginImplementation(PluginImplementation pluginImplementation, bool isAutoEnable = false)
{ {
_logger.Debug("Enabling plugin {pluginInfo}", pluginImplementation.PluginInfo); _logger.Debug("Enabling plugin implementation {implementation} - {plugin}", pluginImplementation, pluginImplementation.Plugin);
OnPluginEnabling(new PluginEventArgs(pluginImplementation.PluginInfo));
lock (_plugins) lock (_plugins)
{ {
@ -306,10 +316,10 @@ namespace Artemis.Core.Services
} }
} }
OnPluginEnabled(new PluginEventArgs(pluginImplementation.PluginInfo)); OnPluginImplementationEnabled(new PluginImplementationEventArgs(pluginImplementation));
} }
public void DisablePlugin(PluginImplementation pluginImplementation) public void DisablePluginImplementation(PluginImplementation pluginImplementation)
{ {
lock (_plugins) lock (_plugins)
{ {
@ -335,9 +345,12 @@ namespace Artemis.Core.Services
OnPluginDisabled(new PluginEventArgs(pluginImplementation.PluginInfo)); OnPluginDisabled(new PluginEventArgs(pluginImplementation.PluginInfo));
} }
#endregion
public PluginInfo GetPluginInfo(PluginImplementation pluginImplementation) public PluginInfo GetPluginInfo(PluginImplementation pluginImplementation)
{ {
return _plugins.FirstOrDefault(p => p.Instance == pluginImplementation); return _plugins.FirstOrDefault(p => p.Plugin == pluginImplementation);
} }
public List<PluginInfo> GetAllPluginInfo() public List<PluginInfo> GetAllPluginInfo()
@ -347,12 +360,12 @@ namespace Artemis.Core.Services
public List<T> GetPluginsOfType<T>() where T : PluginImplementation public List<T> GetPluginsOfType<T>() where T : PluginImplementation
{ {
return _plugins.Where(p => p.IsEnabled && p.Instance is T).Select(p => (T) p.Instance).ToList(); return _plugins.Where(p => p.IsEnabled && p.Plugin is T).Select(p => (T) p.Plugin).ToList();
} }
public PluginImplementation GetPluginByAssembly(Assembly assembly) public PluginImplementation GetPluginByAssembly(Assembly assembly)
{ {
return _plugins.FirstOrDefault(p => p.Assembly == assembly)?.Instance; return _plugins.FirstOrDefault(p => p.Assembly == assembly)?.Plugin;
} }
public PluginImplementation GetPluginByDevice(IRGBDevice rgbDevice) public PluginImplementation GetPluginByDevice(IRGBDevice rgbDevice)
@ -362,8 +375,8 @@ namespace Artemis.Core.Services
public PluginImplementation GetCallingPlugin() public PluginImplementation GetCallingPlugin()
{ {
StackTrace stackTrace = new StackTrace(); // get call stack StackTrace stackTrace = new StackTrace(); // get call stack
StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames)
foreach (StackFrame stackFrame in stackFrames) foreach (StackFrame stackFrame in stackFrames)
{ {
@ -395,7 +408,7 @@ namespace Artemis.Core.Services
if (createLockFile) if (createLockFile)
File.Create(Path.Combine(pluginDirectory.FullName, "artemis.lock")).Close(); File.Create(Path.Combine(pluginDirectory.FullName, "artemis.lock")).Close();
} }
#region Events #region Events
public event EventHandler CopyingBuildInPlugins; public event EventHandler CopyingBuildInPlugins;
@ -406,6 +419,9 @@ namespace Artemis.Core.Services
public event EventHandler<PluginEventArgs> PluginEnabled; public event EventHandler<PluginEventArgs> PluginEnabled;
public event EventHandler<PluginEventArgs> PluginDisabled; public event EventHandler<PluginEventArgs> PluginDisabled;
public event EventHandler<PluginImplementationEventArgs> PluginImplementationEnabled;
public event EventHandler<PluginImplementationEventArgs> PluginImplementationDisabled;
protected virtual void OnCopyingBuildInPlugins() protected virtual void OnCopyingBuildInPlugins()
{ {
CopyingBuildInPlugins?.Invoke(this, EventArgs.Empty); CopyingBuildInPlugins?.Invoke(this, EventArgs.Empty);
@ -441,6 +457,16 @@ namespace Artemis.Core.Services
PluginDisabled?.Invoke(this, e); PluginDisabled?.Invoke(this, e);
} }
protected virtual void OnPluginImplementationDisabled(PluginImplementationEventArgs e)
{
PluginImplementationDisabled?.Invoke(this, e);
}
protected virtual void OnPluginImplementationEnabled(PluginImplementationEventArgs e)
{
PluginImplementationEnabled?.Invoke(this, e);
}
#endregion #endregion
} }
} }

View File

@ -8,16 +8,16 @@ namespace Artemis.Core.Services
{ {
internal class DataModelService : IDataModelService internal class DataModelService : IDataModelService
{ {
public DataModelService(IPluginService pluginService) public DataModelService(IPluginManagementService pluginManagementService)
{ {
// Add data models of already loaded plugins // Add data models of already loaded plugins
foreach (Module module in pluginService.GetPluginsOfType<Module>().Where(p => p.IsEnabled)) foreach (Module module in pluginManagementService.GetPluginsOfType<Module>().Where(p => p.IsEnabled))
AddModuleDataModel(module); AddModuleDataModel(module);
foreach (BaseDataModelExpansion dataModelExpansion in pluginService.GetPluginsOfType<BaseDataModelExpansion>().Where(p => p.IsEnabled)) foreach (BaseDataModelExpansion dataModelExpansion in pluginManagementService.GetPluginsOfType<BaseDataModelExpansion>().Where(p => p.IsEnabled))
AddDataModelExpansionDataModel(dataModelExpansion); AddDataModelExpansionDataModel(dataModelExpansion);
// Add data models of new plugins when they get enabled // Add data models of new plugins when they get enabled
pluginService.PluginEnabled += PluginServiceOnPluginEnabled; pluginManagementService.PluginEnabled += PluginServiceOnPluginEnabled;
} }
public DataModelRegistration RegisterDataModel(DataModel dataModel) public DataModelRegistration RegisterDataModel(DataModel dataModel)
@ -56,9 +56,9 @@ namespace Artemis.Core.Services
private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e) private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e)
{ {
if (e.PluginInfo.Instance is Module module) if (e.PluginInfo.Plugin is Module module)
AddModuleDataModel(module); AddModuleDataModel(module);
else if (e.PluginInfo.Instance is BaseDataModelExpansion dataModelExpansion) else if (e.PluginInfo.Plugin is BaseDataModelExpansion dataModelExpansion)
AddDataModelExpansionDataModel(dataModelExpansion); AddDataModelExpansionDataModel(dataModelExpansion);
} }

View File

@ -13,19 +13,19 @@ namespace Artemis.Core.Services
internal class ProfileService : IProfileService internal class ProfileService : IProfileService
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
private readonly IProfileRepository _profileRepository; private readonly IProfileRepository _profileRepository;
private readonly ISurfaceService _surfaceService; private readonly ISurfaceService _surfaceService;
internal ProfileService(ILogger logger, internal ProfileService(ILogger logger,
IPluginService pluginService, IPluginManagementService pluginManagementService,
ISurfaceService surfaceService, ISurfaceService surfaceService,
IConditionOperatorService conditionOperatorService, IConditionOperatorService conditionOperatorService,
IDataBindingService dataBindingService, IDataBindingService dataBindingService,
IProfileRepository profileRepository) IProfileRepository profileRepository)
{ {
_logger = logger; _logger = logger;
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
_surfaceService = surfaceService; _surfaceService = surfaceService;
_profileRepository = profileRepository; _profileRepository = profileRepository;
@ -118,15 +118,15 @@ namespace Artemis.Core.Services
} }
// This could happen during activation so subscribe to it // This could happen during activation so subscribe to it
_pluginService.PluginEnabled += ActivatingProfilePluginToggle; _pluginManagementService.PluginEnabled += ActivatingProfilePluginToggle;
_pluginService.PluginDisabled += ActivatingProfilePluginToggle; _pluginManagementService.PluginDisabled += ActivatingProfilePluginToggle;
_surfaceService.SurfaceConfigurationUpdated += ActivatingProfileSurfaceUpdate; _surfaceService.SurfaceConfigurationUpdated += ActivatingProfileSurfaceUpdate;
await profileDescriptor.ProfileModule.ChangeActiveProfileAnimated(profile, _surfaceService.ActiveSurface); await profileDescriptor.ProfileModule.ChangeActiveProfileAnimated(profile, _surfaceService.ActiveSurface);
SaveActiveProfile(profileDescriptor.ProfileModule); SaveActiveProfile(profileDescriptor.ProfileModule);
_pluginService.PluginEnabled -= ActivatingProfilePluginToggle; _pluginManagementService.PluginEnabled -= ActivatingProfilePluginToggle;
_pluginService.PluginDisabled -= ActivatingProfilePluginToggle; _pluginManagementService.PluginDisabled -= ActivatingProfilePluginToggle;
_surfaceService.SurfaceConfigurationUpdated -= ActivatingProfileSurfaceUpdate; _surfaceService.SurfaceConfigurationUpdated -= ActivatingProfileSurfaceUpdate;
return profile; return profile;
@ -285,7 +285,7 @@ namespace Artemis.Core.Services
/// <param name="surface"></param> /// <param name="surface"></param>
private void ActiveProfilesPopulateLeds(ArtemisSurface surface) private void ActiveProfilesPopulateLeds(ArtemisSurface surface)
{ {
List<ProfileModule> profileModules = _pluginService.GetPluginsOfType<ProfileModule>(); List<ProfileModule> profileModules = _pluginManagementService.GetPluginsOfType<ProfileModule>();
foreach (ProfileModule profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList()) foreach (ProfileModule profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList())
profileModule.ActiveProfile.PopulateLeds(surface); profileModule.ActiveProfile.PopulateLeds(surface);
} }

View File

@ -12,18 +12,18 @@ namespace Artemis.Core.Services
internal class SurfaceService : ISurfaceService internal class SurfaceService : ISurfaceService
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
private readonly PluginSetting<double> _renderScaleSetting; private readonly PluginSetting<double> _renderScaleSetting;
private readonly IRgbService _rgbService; private readonly IRgbService _rgbService;
private readonly List<ArtemisSurface> _surfaceConfigurations; private readonly List<ArtemisSurface> _surfaceConfigurations;
private readonly ISurfaceRepository _surfaceRepository; private readonly ISurfaceRepository _surfaceRepository;
public SurfaceService(ILogger logger, ISurfaceRepository surfaceRepository, IRgbService rgbService, IPluginService pluginService, ISettingsService settingsService) public SurfaceService(ILogger logger, ISurfaceRepository surfaceRepository, IRgbService rgbService, IPluginManagementService pluginManagementService, ISettingsService settingsService)
{ {
_logger = logger; _logger = logger;
_surfaceRepository = surfaceRepository; _surfaceRepository = surfaceRepository;
_rgbService = rgbService; _rgbService = rgbService;
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
_surfaceConfigurations = new List<ArtemisSurface>(); _surfaceConfigurations = new List<ArtemisSurface>();
_renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 0.5); _renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 0.5);
@ -44,7 +44,7 @@ namespace Artemis.Core.Services
// Add all current devices // Add all current devices
foreach (IRGBDevice rgbDevice in _rgbService.LoadedDevices) foreach (IRGBDevice rgbDevice in _rgbService.LoadedDevices)
{ {
PluginImplementation pluginImplementation = _pluginService.GetPluginByDevice(rgbDevice); PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(rgbDevice);
configuration.Devices.Add(new ArtemisDevice(rgbDevice, pluginImplementation, configuration)); configuration.Devices.Add(new ArtemisDevice(rgbDevice, pluginImplementation, configuration));
} }
@ -136,7 +136,7 @@ namespace Artemis.Core.Services
IRGBDevice device = _rgbService.Surface.Devices.FirstOrDefault(d => d.GetDeviceIdentifier() == position.DeviceIdentifier); IRGBDevice device = _rgbService.Surface.Devices.FirstOrDefault(d => d.GetDeviceIdentifier() == position.DeviceIdentifier);
if (device != null) if (device != null)
{ {
PluginImplementation pluginImplementation = _pluginService.GetPluginByDevice(device); PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(device);
surfaceConfiguration.Devices.Add(new ArtemisDevice(device, pluginImplementation, surfaceConfiguration, position)); surfaceConfiguration.Devices.Add(new ArtemisDevice(device, pluginImplementation, surfaceConfiguration, position));
} }
} }
@ -178,7 +178,7 @@ namespace Artemis.Core.Services
DeviceEntity existingDeviceConfig = surface.SurfaceEntity.DeviceEntities.FirstOrDefault(d => d.DeviceIdentifier == deviceIdentifier); DeviceEntity existingDeviceConfig = surface.SurfaceEntity.DeviceEntities.FirstOrDefault(d => d.DeviceIdentifier == deviceIdentifier);
if (existingDeviceConfig != null) if (existingDeviceConfig != null)
{ {
PluginImplementation pluginImplementation = _pluginService.GetPluginByDevice(rgbDevice); PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(rgbDevice);
device = new ArtemisDevice(rgbDevice, pluginImplementation, surface, existingDeviceConfig); device = new ArtemisDevice(rgbDevice, pluginImplementation, surface, existingDeviceConfig);
} }
// Fall back on creating a new device // Fall back on creating a new device
@ -189,7 +189,7 @@ namespace Artemis.Core.Services
rgbDevice.DeviceInfo, rgbDevice.DeviceInfo,
deviceIdentifier deviceIdentifier
); );
PluginImplementation pluginImplementation = _pluginService.GetPluginByDevice(rgbDevice); PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(rgbDevice);
device = new ArtemisDevice(rgbDevice, pluginImplementation, surface); device = new ArtemisDevice(rgbDevice, pluginImplementation, surface);
} }

View File

@ -16,7 +16,7 @@ namespace Artemis.Core
if (Registrations.Any(r => r.ConditionOperator == conditionOperator)) if (Registrations.Any(r => r.ConditionOperator == conditionOperator))
throw new ArtemisCoreException($"Condition operator store store already contains operator '{conditionOperator.Description}'"); throw new ArtemisCoreException($"Condition operator store store already contains operator '{conditionOperator.Description}'");
registration = new ConditionOperatorRegistration(conditionOperator, conditionOperator.PluginInfo.Instance) {IsInStore = true}; registration = new ConditionOperatorRegistration(conditionOperator, conditionOperator.PluginInfo.Plugin) {IsInStore = true};
Registrations.Add(registration); Registrations.Add(registration);
} }

View File

@ -16,7 +16,7 @@ namespace Artemis.Core
if (Registrations.Any(r => r.DataBindingModifierType == modifierType)) if (Registrations.Any(r => r.DataBindingModifierType == modifierType))
throw new ArtemisCoreException($"Data binding modifier type store already contains modifier '{modifierType.Name}'"); throw new ArtemisCoreException($"Data binding modifier type store already contains modifier '{modifierType.Name}'");
typeRegistration = new DataBindingModifierTypeRegistration(modifierType, modifierType.PluginInfo.Instance) { IsInStore = true }; typeRegistration = new DataBindingModifierTypeRegistration(modifierType, modifierType.PluginInfo.Plugin) { IsInStore = true };
Registrations.Add(typeRegistration); Registrations.Add(typeRegistration);
} }

View File

@ -17,7 +17,7 @@ namespace Artemis.Core
if (Registrations.Any(r => r.LayerBrushDescriptor == descriptor)) if (Registrations.Any(r => r.LayerBrushDescriptor == descriptor))
throw new ArtemisCoreException($"Store already contains layer brush '{descriptor.DisplayName}'"); throw new ArtemisCoreException($"Store already contains layer brush '{descriptor.DisplayName}'");
registration = new LayerBrushRegistration(descriptor, descriptor.LayerBrushProvider.PluginInfo.Instance) {IsInStore = true}; registration = new LayerBrushRegistration(descriptor, descriptor.LayerBrushProvider.PluginInfo.Plugin) {IsInStore = true};
Registrations.Add(registration); Registrations.Add(registration);
} }

View File

@ -17,7 +17,7 @@ namespace Artemis.Core
if (Registrations.Any(r => r.LayerEffectDescriptor == descriptor)) if (Registrations.Any(r => r.LayerEffectDescriptor == descriptor))
throw new ArtemisCoreException($"Store already contains layer brush '{descriptor.DisplayName}'"); throw new ArtemisCoreException($"Store already contains layer brush '{descriptor.DisplayName}'");
registration = new LayerEffectRegistration(descriptor, descriptor.LayerEffectProvider.PluginInfo.Instance) { IsInStore = true }; registration = new LayerEffectRegistration(descriptor, descriptor.LayerEffectProvider.PluginInfo.Plugin) { IsInStore = true };
Registrations.Add(registration); Registrations.Add(registration);
} }

View File

@ -9,7 +9,7 @@ namespace Artemis.Core
{ {
public CorePluginImplementation() public CorePluginImplementation()
{ {
Constants.CorePluginInfo.Instance = this; Constants.CorePluginInfo.Plugin = this;
IsEnabled = true; IsEnabled = true;
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
namespace Artemis.Storage.Entities.Plugins namespace Artemis.Storage.Entities.Plugins
{ {
@ -9,5 +10,16 @@ namespace Artemis.Storage.Entities.Plugins
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public bool IsEnabled { get; set; } public bool IsEnabled { get; set; }
public List<PluginImplementationEntity> Implementations { get; set; }
}
/// <summary>
/// Represents the configuration of a plugin implementation, each implementation has one configuration
/// </summary>
public class PluginImplementationEntity
{
public string Type { get; set; }
public bool IsEnabled { get; set; }
} }
} }

View File

@ -22,7 +22,7 @@ namespace Artemis.UI.Shared
ViewModelType = viewModelType; ViewModelType = viewModelType;
if (PluginInfo != Constants.CorePluginInfo) if (PluginInfo != Constants.CorePluginInfo)
PluginInfo.Instance.Disabled += InstanceOnDisabled; PluginInfo.Plugin.Disabled += InstanceOnDisabled;
} }
public RegistrationType RegistrationType { get; } public RegistrationType RegistrationType { get; }
@ -35,7 +35,7 @@ namespace Artemis.UI.Shared
internal void Unsubscribe() internal void Unsubscribe()
{ {
if (PluginInfo != Constants.CorePluginInfo) if (PluginInfo != Constants.CorePluginInfo)
PluginInfo.Instance.Disabled -= InstanceOnDisabled; PluginInfo.Plugin.Disabled -= InstanceOnDisabled;
} }
private void InstanceOnDisabled(object sender, EventArgs e) private void InstanceOnDisabled(object sender, EventArgs e)

View File

@ -16,7 +16,7 @@ namespace Artemis.UI.Shared
ViewModelType = viewModelType; ViewModelType = viewModelType;
if (PluginInfo != Constants.CorePluginInfo) if (PluginInfo != Constants.CorePluginInfo)
PluginInfo.Instance.Disabled += InstanceOnDisabled; PluginInfo.Plugin.Disabled += InstanceOnDisabled;
} }
public PluginInfo PluginInfo { get; } public PluginInfo PluginInfo { get; }
@ -26,7 +26,7 @@ namespace Artemis.UI.Shared
internal void Unsubscribe() internal void Unsubscribe()
{ {
if (PluginInfo != Constants.CorePluginInfo) if (PluginInfo != Constants.CorePluginInfo)
PluginInfo.Instance.Disabled -= InstanceOnDisabled; PluginInfo.Plugin.Disabled -= InstanceOnDisabled;
} }
private void InstanceOnDisabled(object sender, EventArgs e) private void InstanceOnDisabled(object sender, EventArgs e)

View File

@ -22,14 +22,14 @@ namespace Artemis.UI.Shared.Services
private readonly IKernel _kernel; private readonly IKernel _kernel;
private readonly IViewManager _viewManager; private readonly IViewManager _viewManager;
private readonly IWindowManager _windowManager; private readonly IWindowManager _windowManager;
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
public DialogService(IKernel kernel, IViewManager viewManager, IWindowManager windowManager, IPluginService pluginService) public DialogService(IKernel kernel, IViewManager viewManager, IWindowManager windowManager, IPluginManagementService pluginManagementService)
{ {
_kernel = kernel; _kernel = kernel;
_viewManager = viewManager; _viewManager = viewManager;
_windowManager = windowManager; _windowManager = windowManager;
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
} }
private async Task<object> ShowDialog<T>(IParameter[] parameters) where T : DialogViewModelBase private async Task<object> ShowDialog<T>(IParameter[] parameters) where T : DialogViewModelBase
@ -109,7 +109,7 @@ namespace Artemis.UI.Shared.Services
private async Task<object> ShowDialogAt<T>(string identifier, IParameter[] parameters) where T : DialogViewModelBase private async Task<object> ShowDialogAt<T>(string identifier, IParameter[] parameters) where T : DialogViewModelBase
{ {
PluginImplementation callingPluginImplementation = _pluginService.GetCallingPlugin(); PluginImplementation callingPluginImplementation = _pluginManagementService.GetCallingPlugin();
if (parameters == null) throw new ArgumentNullException(nameof(parameters)); if (parameters == null) throw new ArgumentNullException(nameof(parameters));
if (callingPluginImplementation != null) if (callingPluginImplementation != null)

View File

@ -11,17 +11,17 @@ namespace Artemis.UI.PropertyInput
{ {
public class BrushPropertyInputViewModel : PropertyInputViewModel<LayerBrushReference> public class BrushPropertyInputViewModel : PropertyInputViewModel<LayerBrushReference>
{ {
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
private BindableCollection<LayerBrushDescriptor> _descriptors; private BindableCollection<LayerBrushDescriptor> _descriptors;
public BrushPropertyInputViewModel(LayerProperty<LayerBrushReference> layerProperty, public BrushPropertyInputViewModel(LayerProperty<LayerBrushReference> layerProperty,
IProfileEditorService profileEditorService, IProfileEditorService profileEditorService,
IPluginService pluginService) : base(layerProperty, profileEditorService) IPluginManagementService pluginManagementService) : base(layerProperty, profileEditorService)
{ {
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
_pluginService.PluginEnabled += PluginServiceOnPluginLoaded; _pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementLoaded;
_pluginService.PluginDisabled += PluginServiceOnPluginLoaded; _pluginManagementService.PluginDisabled += PluginManagementServiceOnPluginManagementLoaded;
UpdateEnumValues(); UpdateEnumValues();
} }
@ -39,7 +39,7 @@ namespace Artemis.UI.PropertyInput
public void UpdateEnumValues() public void UpdateEnumValues()
{ {
List<LayerBrushProvider> layerBrushProviders = _pluginService.GetPluginsOfType<LayerBrushProvider>(); List<LayerBrushProvider> layerBrushProviders = _pluginManagementService.GetPluginsOfType<LayerBrushProvider>();
Descriptors = new BindableCollection<LayerBrushDescriptor>(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors)); Descriptors = new BindableCollection<LayerBrushDescriptor>(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors));
NotifyOfPropertyChange(nameof(SelectedDescriptor)); NotifyOfPropertyChange(nameof(SelectedDescriptor));
} }
@ -47,8 +47,8 @@ namespace Artemis.UI.PropertyInput
public override void Dispose() public override void Dispose()
{ {
_pluginService.PluginEnabled -= PluginServiceOnPluginLoaded; _pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginManagementLoaded;
_pluginService.PluginDisabled -= PluginServiceOnPluginLoaded; _pluginManagementService.PluginDisabled -= PluginManagementServiceOnPluginManagementLoaded;
base.Dispose(); base.Dispose();
} }
@ -63,7 +63,7 @@ namespace Artemis.UI.PropertyInput
InputValue = new LayerBrushReference(value); InputValue = new LayerBrushReference(value);
} }
private void PluginServiceOnPluginLoaded(object sender, PluginEventArgs e) private void PluginManagementServiceOnPluginManagementLoaded(object sender, PluginEventArgs e)
{ {
UpdateEnumValues(); UpdateEnumValues();
} }

View File

@ -12,13 +12,13 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.LayerEffects
{ {
public class EffectsViewModel : Conductor<LayerEffectDescriptor>.Collection.AllActive public class EffectsViewModel : Conductor<LayerEffectDescriptor>.Collection.AllActive
{ {
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
private readonly IProfileEditorService _profileEditorService; private readonly IProfileEditorService _profileEditorService;
private LayerEffectDescriptor _selectedLayerEffectDescriptor; private LayerEffectDescriptor _selectedLayerEffectDescriptor;
public EffectsViewModel(LayerPropertiesViewModel layerPropertiesViewModel, IPluginService pluginService, IProfileEditorService profileEditorService) public EffectsViewModel(LayerPropertiesViewModel layerPropertiesViewModel, IPluginManagementService pluginManagementService, IProfileEditorService profileEditorService)
{ {
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
_profileEditorService = profileEditorService; _profileEditorService = profileEditorService;
LayerPropertiesViewModel = layerPropertiesViewModel; LayerPropertiesViewModel = layerPropertiesViewModel;
PropertyChanged += HandleSelectedLayerEffectChanged; PropertyChanged += HandleSelectedLayerEffectChanged;
@ -35,7 +35,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.LayerEffects
public void PopulateDescriptors() public void PopulateDescriptors()
{ {
List<LayerEffectProvider> layerBrushProviders = _pluginService.GetPluginsOfType<LayerEffectProvider>(); List<LayerEffectProvider> layerBrushProviders = _pluginManagementService.GetPluginsOfType<LayerEffectProvider>();
List<LayerEffectDescriptor> descriptors = layerBrushProviders.SelectMany(l => l.LayerEffectDescriptors).ToList(); List<LayerEffectDescriptor> descriptors = layerBrushProviders.SelectMany(l => l.LayerEffectDescriptors).ToList();
Items.AddRange(descriptors.Except(Items)); Items.AddRange(descriptors.Except(Items));
Items.RemoveRange(Items.Except(descriptors)); Items.RemoveRange(Items.Except(descriptors));

View File

@ -13,7 +13,7 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
public class DataModelDebugViewModel : Screen public class DataModelDebugViewModel : Screen
{ {
private readonly IDataModelUIService _dataModelUIService; private readonly IDataModelUIService _dataModelUIService;
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
private readonly Timer _updateTimer; private readonly Timer _updateTimer;
private bool _isModuleFilterEnabled; private bool _isModuleFilterEnabled;
private DataModelPropertiesViewModel _mainDataModel; private DataModelPropertiesViewModel _mainDataModel;
@ -21,10 +21,10 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
private string _propertySearch; private string _propertySearch;
private Module _selectedModule; private Module _selectedModule;
public DataModelDebugViewModel(IDataModelUIService dataModelUIService, IPluginService pluginService) public DataModelDebugViewModel(IDataModelUIService dataModelUIService, IPluginManagementService pluginManagementService)
{ {
_dataModelUIService = dataModelUIService; _dataModelUIService = dataModelUIService;
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
_updateTimer = new Timer(500); _updateTimer = new Timer(500);
DisplayName = "Data model"; DisplayName = "Data model";
@ -77,8 +77,8 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
GetDataModel(); GetDataModel();
_updateTimer.Start(); _updateTimer.Start();
_updateTimer.Elapsed += OnUpdateTimerOnElapsed; _updateTimer.Elapsed += OnUpdateTimerOnElapsed;
_pluginService.PluginEnabled += PluginServiceOnPluginToggled; _pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementToggled;
_pluginService.PluginDisabled += PluginServiceOnPluginToggled; _pluginManagementService.PluginDisabled += PluginManagementServiceOnPluginManagementToggled;
PopulateModules(); PopulateModules();
@ -89,8 +89,8 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
{ {
_updateTimer.Stop(); _updateTimer.Stop();
_updateTimer.Elapsed -= OnUpdateTimerOnElapsed; _updateTimer.Elapsed -= OnUpdateTimerOnElapsed;
_pluginService.PluginEnabled -= PluginServiceOnPluginToggled; _pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginManagementToggled;
_pluginService.PluginDisabled -= PluginServiceOnPluginToggled; _pluginManagementService.PluginDisabled -= PluginManagementServiceOnPluginManagementToggled;
base.OnDeactivate(); base.OnDeactivate();
} }
@ -110,14 +110,14 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
: _dataModelUIService.GetMainDataModelVisualization(); : _dataModelUIService.GetMainDataModelVisualization();
} }
private void PluginServiceOnPluginToggled(object? sender, PluginEventArgs e) private void PluginManagementServiceOnPluginManagementToggled(object? sender, PluginEventArgs e)
{ {
PopulateModules(); PopulateModules();
} }
private void PopulateModules() private void PopulateModules()
{ {
Modules = _pluginService.GetPluginsOfType<Module>().Where(p => p.IsEnabled).ToList(); Modules = _pluginManagementService.GetPluginsOfType<Module>().Where(p => p.IsEnabled).ToList();
} }
} }
} }

View File

@ -25,7 +25,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
private List<Tuple<string, int>> _targetFrameRates; private List<Tuple<string, int>> _targetFrameRates;
private readonly PluginSetting<LayerBrushReference> _defaultLayerBrushDescriptor; private readonly PluginSetting<LayerBrushReference> _defaultLayerBrushDescriptor;
public GeneralSettingsTabViewModel(IDialogService dialogService, IDebugService debugService, ISettingsService settingsService, IPluginService pluginService) public GeneralSettingsTabViewModel(IDialogService dialogService, IDebugService debugService, ISettingsService settingsService, IPluginManagementService pluginManagementService)
{ {
DisplayName = "GENERAL"; DisplayName = "GENERAL";
@ -46,7 +46,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
// Anything else is kinda broken right now // Anything else is kinda broken right now
SampleSizes = new List<int> {1, 9}; SampleSizes = new List<int> {1, 9};
List<LayerBrushProvider> layerBrushProviders = pluginService.GetPluginsOfType<LayerBrushProvider>(); List<LayerBrushProvider> layerBrushProviders = pluginManagementService.GetPluginsOfType<LayerBrushProvider>();
LayerBrushDescriptors = new BindableCollection<LayerBrushDescriptor>(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors)); LayerBrushDescriptors = new BindableCollection<LayerBrushDescriptor>(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors));
_defaultLayerBrushDescriptor = _settingsService.GetSetting("ProfileEditor.DefaultLayerBrushDescriptor", new LayerBrushReference _defaultLayerBrushDescriptor = _settingsService.GetSetting("ProfileEditor.DefaultLayerBrushDescriptor", new LayerBrushReference

View File

@ -10,17 +10,17 @@ namespace Artemis.UI.Screens.Settings.Tabs.Modules
public class ModuleOrderTabViewModel : Screen, IDropTarget public class ModuleOrderTabViewModel : Screen, IDropTarget
{ {
private readonly IModuleService _moduleService; private readonly IModuleService _moduleService;
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
private readonly DefaultDropHandler _defaultDropHandler; private readonly DefaultDropHandler _defaultDropHandler;
private readonly List<ModuleOrderModuleViewModel> _modules; private readonly List<ModuleOrderModuleViewModel> _modules;
public ModuleOrderTabViewModel(IPluginService pluginService, IModuleService moduleService) public ModuleOrderTabViewModel(IPluginManagementService pluginManagementService, IModuleService moduleService)
{ {
DisplayName = "MODULE PRIORITY"; DisplayName = "MODULE PRIORITY";
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
_moduleService = moduleService; _moduleService = moduleService;
_modules = new List<ModuleOrderModuleViewModel>(pluginService.GetPluginsOfType<Module>().Select(m => new ModuleOrderModuleViewModel(m))); _modules = new List<ModuleOrderModuleViewModel>(pluginManagementService.GetPluginsOfType<Module>().Select(m => new ModuleOrderModuleViewModel(m)));
_defaultDropHandler = new DefaultDropHandler(); _defaultDropHandler = new DefaultDropHandler();
NormalModules = new BindableCollection<ModuleOrderModuleViewModel>(); NormalModules = new BindableCollection<ModuleOrderModuleViewModel>();

View File

@ -9,15 +9,15 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
{ {
public class PluginSettingsTabViewModel : Conductor<PluginSettingsViewModel>.Collection.AllActive public class PluginSettingsTabViewModel : Conductor<PluginSettingsViewModel>.Collection.AllActive
{ {
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
private readonly ISettingsVmFactory _settingsVmFactory; private readonly ISettingsVmFactory _settingsVmFactory;
private BindableCollection<PluginSettingsViewModel> _plugins; private BindableCollection<PluginSettingsViewModel> _plugins;
public PluginSettingsTabViewModel(IPluginService pluginService, ISettingsVmFactory settingsVmFactory) public PluginSettingsTabViewModel(IPluginManagementService pluginManagementService, ISettingsVmFactory settingsVmFactory)
{ {
DisplayName = "PLUGINS"; DisplayName = "PLUGINS";
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
_settingsVmFactory = settingsVmFactory; _settingsVmFactory = settingsVmFactory;
} }
@ -29,7 +29,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
Items.Clear(); Items.Clear();
await Task.Delay(200); await Task.Delay(200);
List<PluginSettingsViewModel> instances = _pluginService.GetAllPluginInfo().Select(p => _settingsVmFactory.CreatePluginSettingsViewModel(p.Instance)).ToList(); List<PluginSettingsViewModel> instances = _pluginManagementService.GetAllPluginInfo().Select(p => _settingsVmFactory.CreatePluginSettingsViewModel(p.Plugin)).ToList();
foreach (PluginSettingsViewModel pluginSettingsViewModel in instances) foreach (PluginSettingsViewModel pluginSettingsViewModel in instances)
Items.Add(pluginSettingsViewModel); Items.Add(pluginSettingsViewModel);
}); });

View File

@ -26,7 +26,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
{ {
private readonly IDialogService _dialogService; private readonly IDialogService _dialogService;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
private readonly ISnackbarMessageQueue _snackbarMessageQueue; private readonly ISnackbarMessageQueue _snackbarMessageQueue;
private readonly IWindowManager _windowManager; private readonly IWindowManager _windowManager;
private bool _enabling; private bool _enabling;
@ -37,7 +37,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
ILogger logger, ILogger logger,
IWindowManager windowManager, IWindowManager windowManager,
IDialogService dialogService, IDialogService dialogService,
IPluginService pluginService, IPluginManagementService pluginManagementService,
ISnackbarMessageQueue snackbarMessageQueue) ISnackbarMessageQueue snackbarMessageQueue)
{ {
PluginImplementation = pluginImplementation; PluginImplementation = pluginImplementation;
@ -46,7 +46,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
_logger = logger; _logger = logger;
_windowManager = windowManager; _windowManager = windowManager;
_dialogService = dialogService; _dialogService = dialogService;
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
_snackbarMessageQueue = snackbarMessageQueue; _snackbarMessageQueue = snackbarMessageQueue;
} }
@ -183,7 +183,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
try try
{ {
_pluginService.EnablePlugin(PluginImplementation); _pluginManagementService.EnablePluginImplementation(PluginImplementation);
} }
catch (Exception e) catch (Exception e)
{ {
@ -195,7 +195,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
} }
} }
else else
_pluginService.DisablePlugin(PluginImplementation); _pluginManagementService.DisablePluginImplementation(PluginImplementation);
NotifyOfPropertyChange(nameof(IsEnabled)); NotifyOfPropertyChange(nameof(IsEnabled));
NotifyOfPropertyChange(nameof(CanOpenSettings)); NotifyOfPropertyChange(nameof(CanOpenSettings));
@ -208,7 +208,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
bool restart = false; bool restart = false;
// If any plugin already requires a restart, don't ask the user again // If any plugin already requires a restart, don't ask the user again
bool restartQueued = _pluginService.GetAllPluginInfo().Any(p => p.Instance != null && !p.IsEnabled && p.Instance.IsEnabled); bool restartQueued = _pluginManagementService.GetAllPluginInfo().Any(p => p.Plugin != null && !p.IsEnabled && p.Plugin.IsEnabled);
// If the plugin isn't enabled (load failed), it can be disabled without a restart // If the plugin isn't enabled (load failed), it can be disabled without a restart
if (!restartQueued && PluginImplementation.IsEnabled) if (!restartQueued && PluginImplementation.IsEnabled)
{ {
@ -220,7 +220,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
); );
} }
_pluginService.DisablePlugin(PluginImplementation); _pluginManagementService.DisablePluginImplementation(PluginImplementation);
if (restart) if (restart)
{ {
_logger.Debug("Restarting for device provider disable {pluginInfo}", PluginImplementation.PluginInfo); _logger.Debug("Restarting for device provider disable {pluginInfo}", PluginImplementation.PluginInfo);

View File

@ -29,18 +29,18 @@ namespace Artemis.UI.Screens.Sidebar
private readonly Timer _activeModulesUpdateTimer; private readonly Timer _activeModulesUpdateTimer;
private readonly IKernel _kernel; private readonly IKernel _kernel;
private readonly IModuleVmFactory _moduleVmFactory; private readonly IModuleVmFactory _moduleVmFactory;
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
private string _activeModules; private string _activeModules;
private bool _isSidebarOpen; private bool _isSidebarOpen;
private IScreen _selectedItem; private IScreen _selectedItem;
private BindableCollection<INavigationItem> _sidebarItems; private BindableCollection<INavigationItem> _sidebarItems;
private Dictionary<INavigationItem, Module> _sidebarModules; private Dictionary<INavigationItem, Module> _sidebarModules;
public SidebarViewModel(IKernel kernel, IEventAggregator eventAggregator, IModuleVmFactory moduleVmFactory, IPluginService pluginService) public SidebarViewModel(IKernel kernel, IEventAggregator eventAggregator, IModuleVmFactory moduleVmFactory, IPluginManagementService pluginManagementService)
{ {
_kernel = kernel; _kernel = kernel;
_moduleVmFactory = moduleVmFactory; _moduleVmFactory = moduleVmFactory;
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
SidebarModules = new Dictionary<INavigationItem, Module>(); SidebarModules = new Dictionary<INavigationItem, Module>();
SidebarItems = new BindableCollection<INavigationItem>(); SidebarItems = new BindableCollection<INavigationItem>();
@ -49,8 +49,8 @@ namespace Artemis.UI.Screens.Sidebar
_activeModulesUpdateTimer.Start(); _activeModulesUpdateTimer.Start();
_activeModulesUpdateTimer.Elapsed += ActiveModulesUpdateTimerOnElapsed; _activeModulesUpdateTimer.Elapsed += ActiveModulesUpdateTimerOnElapsed;
_pluginService.PluginEnabled += PluginServiceOnPluginEnabled; _pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementEnabled;
_pluginService.PluginDisabled += PluginServiceOnPluginDisabled; _pluginManagementService.PluginDisabled += PluginManagementServiceOnPluginManagementDisabled;
SetupSidebar(); SetupSidebar();
eventAggregator.Subscribe(this); eventAggregator.Subscribe(this);
@ -96,8 +96,8 @@ namespace Artemis.UI.Screens.Sidebar
SelectedItem?.Deactivate(); SelectedItem?.Deactivate();
SelectedItem = null; SelectedItem = null;
_pluginService.PluginEnabled -= PluginServiceOnPluginEnabled; _pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginManagementEnabled;
_pluginService.PluginDisabled -= PluginServiceOnPluginDisabled; _pluginManagementService.PluginDisabled -= PluginManagementServiceOnPluginManagementDisabled;
_activeModulesUpdateTimer.Stop(); _activeModulesUpdateTimer.Stop();
_activeModulesUpdateTimer.Elapsed -= ActiveModulesUpdateTimerOnElapsed; _activeModulesUpdateTimer.Elapsed -= ActiveModulesUpdateTimerOnElapsed;
@ -118,7 +118,7 @@ namespace Artemis.UI.Screens.Sidebar
// Add all activated modules // Add all activated modules
SidebarItems.Add(new DividerNavigationItem()); SidebarItems.Add(new DividerNavigationItem());
SidebarItems.Add(new SubheaderNavigationItem {Subheader = "Modules"}); SidebarItems.Add(new SubheaderNavigationItem {Subheader = "Modules"});
List<Module> modules = _pluginService.GetPluginsOfType<Module>().ToList(); List<Module> modules = _pluginManagementService.GetPluginsOfType<Module>().ToList();
foreach (Module module in modules) foreach (Module module in modules)
AddModule(module); AddModule(module);
@ -210,15 +210,15 @@ namespace Artemis.UI.Screens.Sidebar
#region Event handlers #region Event handlers
private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e) private void PluginManagementServiceOnPluginManagementEnabled(object sender, PluginEventArgs e)
{ {
if (e.PluginInfo.Instance is Module module) if (e.PluginInfo.Plugin is Module module)
AddModule(module); AddModule(module);
} }
private void PluginServiceOnPluginDisabled(object sender, PluginEventArgs e) private void PluginManagementServiceOnPluginManagementDisabled(object sender, PluginEventArgs e)
{ {
if (e.PluginInfo.Instance is Module module) if (e.PluginInfo.Plugin is Module module)
RemoveModule(module); RemoveModule(module);
} }

View File

@ -10,13 +10,13 @@ namespace Artemis.UI.Screens.Splash
public class SplashViewModel : Screen public class SplashViewModel : Screen
{ {
private readonly ICoreService _coreService; private readonly ICoreService _coreService;
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
private string _status; private string _status;
public SplashViewModel(ICoreService coreService, IPluginService pluginService) public SplashViewModel(ICoreService coreService, IPluginManagementService pluginManagementService)
{ {
_coreService = coreService; _coreService = coreService;
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
Status = "Initializing Core"; Status = "Initializing Core";
} }
@ -37,46 +37,46 @@ namespace Artemis.UI.Screens.Splash
protected override void OnInitialActivate() protected override void OnInitialActivate()
{ {
_coreService.Initialized += OnCoreServiceOnInitialized; _coreService.Initialized += OnCoreServiceOnInitialized;
_pluginService.CopyingBuildInPlugins += OnPluginServiceOnCopyingBuildInPlugins; _pluginManagementService.CopyingBuildInPlugins += OnPluginManagementServiceOnCopyingBuildInPluginsManagement;
_pluginService.PluginLoading += OnPluginServiceOnPluginLoading; _pluginManagementService.PluginLoading += OnPluginManagementServiceOnPluginManagementLoading;
_pluginService.PluginLoaded += OnPluginServiceOnPluginLoaded; _pluginManagementService.PluginLoaded += OnPluginManagementServiceOnPluginManagementLoaded;
_pluginService.PluginEnabling += PluginServiceOnPluginEnabling; _pluginManagementService.PluginEnabling += PluginManagementServiceOnPluginManagementEnabling;
_pluginService.PluginEnabled += PluginServiceOnPluginEnabled; _pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementEnabled;
base.OnInitialActivate(); base.OnInitialActivate();
} }
protected override void OnClose() protected override void OnClose()
{ {
_coreService.Initialized -= OnCoreServiceOnInitialized; _coreService.Initialized -= OnCoreServiceOnInitialized;
_pluginService.CopyingBuildInPlugins -= OnPluginServiceOnCopyingBuildInPlugins; _pluginManagementService.CopyingBuildInPlugins -= OnPluginManagementServiceOnCopyingBuildInPluginsManagement;
_pluginService.PluginLoading -= OnPluginServiceOnPluginLoading; _pluginManagementService.PluginLoading -= OnPluginManagementServiceOnPluginManagementLoading;
_pluginService.PluginLoaded -= OnPluginServiceOnPluginLoaded; _pluginManagementService.PluginLoaded -= OnPluginManagementServiceOnPluginManagementLoaded;
_pluginService.PluginEnabling -= PluginServiceOnPluginEnabling; _pluginManagementService.PluginEnabling -= PluginManagementServiceOnPluginManagementEnabling;
_pluginService.PluginEnabled -= PluginServiceOnPluginEnabled; _pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginManagementEnabled;
base.OnClose(); base.OnClose();
} }
private void OnPluginServiceOnPluginLoaded(object sender, PluginEventArgs args) private void OnPluginManagementServiceOnPluginManagementLoaded(object sender, PluginEventArgs args)
{ {
Status = "Initializing UI"; Status = "Initializing UI";
} }
private void OnPluginServiceOnPluginLoading(object sender, PluginEventArgs args) private void OnPluginManagementServiceOnPluginManagementLoading(object sender, PluginEventArgs args)
{ {
Status = "Loading plugin: " + args.PluginInfo.Name; Status = "Loading plugin: " + args.PluginInfo.Name;
} }
private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs args) private void PluginManagementServiceOnPluginManagementEnabled(object sender, PluginEventArgs args)
{ {
Status = "Initializing UI"; Status = "Initializing UI";
} }
private void PluginServiceOnPluginEnabling(object sender, PluginEventArgs args) private void PluginManagementServiceOnPluginManagementEnabling(object sender, PluginEventArgs args)
{ {
Status = "Enabling plugin: " + args.PluginInfo.Name; Status = "Enabling plugin: " + args.PluginInfo.Name;
} }
private void OnPluginServiceOnCopyingBuildInPlugins(object sender, EventArgs args) private void OnPluginManagementServiceOnCopyingBuildInPluginsManagement(object sender, EventArgs args)
{ {
Status = "Updating built-in plugins"; Status = "Updating built-in plugins";
} }

View File

@ -13,19 +13,19 @@ namespace Artemis.UI.Services
{ {
private readonly IDataModelUIService _dataModelUIService; private readonly IDataModelUIService _dataModelUIService;
private readonly IProfileEditorService _profileEditorService; private readonly IProfileEditorService _profileEditorService;
private readonly IPluginService _pluginService; private readonly IPluginManagementService _pluginManagementService;
private bool _registeredBuiltInDataModelDisplays; private bool _registeredBuiltInDataModelDisplays;
private bool _registeredBuiltInDataModelInputs; private bool _registeredBuiltInDataModelInputs;
private bool _registeredBuiltInPropertyEditors; private bool _registeredBuiltInPropertyEditors;
public RegistrationService(IDataModelUIService dataModelUIService, IProfileEditorService profileEditorService, IPluginService pluginService) public RegistrationService(IDataModelUIService dataModelUIService, IProfileEditorService profileEditorService, IPluginManagementService pluginManagementService)
{ {
_dataModelUIService = dataModelUIService; _dataModelUIService = dataModelUIService;
_profileEditorService = profileEditorService; _profileEditorService = profileEditorService;
_pluginService = pluginService; _pluginManagementService = pluginManagementService;
LoadPluginModules(); LoadPluginModules();
pluginService.PluginLoaded += PluginServiceOnPluginLoaded; pluginManagementService.PluginLoaded += PluginServiceOnPluginLoaded;
} }
public void RegisterBuiltInDataModelDisplays() public void RegisterBuiltInDataModelDisplays()
@ -80,7 +80,7 @@ namespace Artemis.UI.Services
private void LoadPluginModules() private void LoadPluginModules()
{ {
foreach (PluginInfo pluginInfo in _pluginService.GetAllPluginInfo()) foreach (PluginInfo pluginInfo in _pluginManagementService.GetAllPluginInfo())
pluginInfo.Kernel.Load(new[] { new PluginUIModule(pluginInfo) }); pluginInfo.Kernel.Load(new[] { new PluginUIModule(pluginInfo) });
} }
} }