From b56966c585110da15f664ca3ba290af45105993a Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 10 Nov 2020 20:51:29 +0100 Subject: [PATCH] Plugins - Reworked most of the activation logic --- .../Events/Plugins/PluginEventArgs.cs | 6 +- .../Plugins/PluginImplementationEventArgs.cs | 18 ++ .../Exceptions/ArtemisPluginException.cs | 14 +- .../Ninject/PluginSettingsProvider.cs | 8 +- src/Artemis.Core/Plugins/Plugin.cs | 121 +++++++++++- .../Plugins/PluginImplementation.cs | 137 +++++++++---- src/Artemis.Core/Plugins/PluginInfo.cs | 90 +-------- .../Plugins/TimedUpdateRegistration.cs | 18 +- src/Artemis.Core/Services/CoreService.cs | 20 +- .../Services/Interfaces/IPluginService.cs | 9 +- src/Artemis.Core/Services/ModuleService.cs | 20 +- src/Artemis.Core/Services/PluginService.cs | 182 ++++++++++-------- .../Services/Registration/DataModelService.cs | 12 +- .../Services/Storage/ProfileService.cs | 16 +- .../Services/Storage/SurfaceService.cs | 14 +- .../Stores/ConditionOperatorStore.cs | 2 +- .../Stores/DataBindingModifierTypeStore.cs | 2 +- src/Artemis.Core/Stores/LayerBrushStore.cs | 2 +- src/Artemis.Core/Stores/LayerEffectStore.cs | 2 +- .../Utilities/CorePluginImplementation.cs | 2 +- .../Entities/Plugins/PluginEntity.cs | 12 ++ .../DataModelVisualizationRegistration.cs | 4 +- .../PropertyInputRegistration.cs | 4 +- .../Services/Dialog/DialogService.cs | 8 +- .../BrushPropertyInputViewModel.cs | 18 +- .../LayerEffects/EffectsViewModel.cs | 8 +- .../Debug/Tabs/DataModelDebugViewModel.cs | 18 +- .../General/GeneralSettingsTabViewModel.cs | 4 +- .../Tabs/Modules/ModuleOrderTabViewModel.cs | 8 +- .../Plugins/PluginSettingsTabViewModel.cs | 8 +- .../Tabs/Plugins/PluginSettingsViewModel.cs | 14 +- .../Screens/Sidebar/SidebarViewModel.cs | 24 +-- .../Screens/Splash/SplashViewModel.cs | 36 ++-- .../Services/RegistrationService.cs | 10 +- 34 files changed, 509 insertions(+), 362 deletions(-) create mode 100644 src/Artemis.Core/Events/Plugins/PluginImplementationEventArgs.cs diff --git a/src/Artemis.Core/Events/Plugins/PluginEventArgs.cs b/src/Artemis.Core/Events/Plugins/PluginEventArgs.cs index 9f69f4974..48e4ec7db 100644 --- a/src/Artemis.Core/Events/Plugins/PluginEventArgs.cs +++ b/src/Artemis.Core/Events/Plugins/PluginEventArgs.cs @@ -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; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Events/Plugins/PluginImplementationEventArgs.cs b/src/Artemis.Core/Events/Plugins/PluginImplementationEventArgs.cs new file mode 100644 index 000000000..45f5639c9 --- /dev/null +++ b/src/Artemis.Core/Events/Plugins/PluginImplementationEventArgs.cs @@ -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; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Exceptions/ArtemisPluginException.cs b/src/Artemis.Core/Exceptions/ArtemisPluginException.cs index c0a889ce1..84c33d8ad 100644 --- a/src/Artemis.Core/Exceptions/ArtemisPluginException.cs +++ b/src/Artemis.Core/Exceptions/ArtemisPluginException.cs @@ -4,19 +4,19 @@ namespace Artemis.Core { 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) @@ -27,6 +27,6 @@ namespace Artemis.Core { } - public PluginInfo PluginInfo { get; } + public Plugin Plugin { get; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Ninject/PluginSettingsProvider.cs b/src/Artemis.Core/Ninject/PluginSettingsProvider.cs index d8ea16a06..559fa4087 100644 --- a/src/Artemis.Core/Ninject/PluginSettingsProvider.cs +++ b/src/Artemis.Core/Ninject/PluginSettingsProvider.cs @@ -10,12 +10,12 @@ namespace Artemis.Core.Ninject { private static readonly List PluginSettings = new List(); 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; - _pluginService = pluginService; + _pluginManagementService = pluginManagementService; } protected override PluginSettings CreateInstance(IContext context) @@ -27,7 +27,7 @@ namespace Artemis.Core.Ninject // First try by PluginInfo parameter PluginInfo pluginInfo = parentRequest.Parameters.FirstOrDefault(p => p.Name == "PluginInfo")?.GetValue(context, null) as PluginInfo; if (pluginInfo == null) - pluginInfo = _pluginService.GetPluginByAssembly(parentRequest.Service.Assembly)?.PluginInfo; + pluginInfo = _pluginManagementService.GetPluginByAssembly(parentRequest.Service.Assembly)?.PluginInfo; // Fall back to assembly based detection if (pluginInfo == null) throw new ArtemisCoreException("PluginSettings can only be injected with the PluginInfo parameter provided " + diff --git a/src/Artemis.Core/Plugins/Plugin.cs b/src/Artemis.Core/Plugins/Plugin.cs index 43d074990..ec42bcdeb 100644 --- a/src/Artemis.Core/Plugins/Plugin.cs +++ b/src/Artemis.Core/Plugins/Plugin.cs @@ -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 { /// /// Represents a plugin /// - public abstract class Plugin + public class Plugin : PropertyChangedBase, IDisposable { + private readonly List _implementations; + + private bool _isEnabled; + + internal Plugin(PluginInfo info, DirectoryInfo directory) + { + Info = info; + Directory = directory; + + _implementations = new List(); + } + + /// + /// Gets the plugin GUID + /// + public Guid Guid => Info.Guid; + /// /// Gets the plugin info related to this plugin /// - public PluginInfo Info { get; internal set; } + public PluginInfo Info { get; } + + /// + /// The plugins root directory + /// + public DirectoryInfo Directory { get; } /// /// Gets or sets a configuration dialog for this plugin that is accessible in the UI under Settings > Plugins /// - public PluginConfigurationDialog ConfigurationDialog { get; protected set; } + public PluginConfigurationDialog? ConfigurationDialog { get; protected set; } + + /// + /// Indicates whether the user enabled the plugin or not + /// + public bool IsEnabled + { + get => _isEnabled; + private set => SetAndNotify(ref _isEnabled, value); + } + + /// + /// Gets a read-only collection of all implementations this plugin provides + /// + public ReadOnlyCollection Implementations => _implementations.AsReadOnly(); + + /// + /// The assembly the plugin code lives in + /// + internal Assembly? Assembly { get; set; } + + /// + /// The Ninject kernel of the plugin + /// + internal IKernel? Kernel { get; set; } + + /// + /// The PluginLoader backing this plugin + /// + internal PluginLoader? PluginLoader { get; set; } + + /// + /// The entity representing the plugin + /// + internal PluginEntity? Entity { get; set; } + + /// + /// Resolves the relative path provided in the parameter to an absolute path + /// + /// The path to resolve + /// An absolute path pointing to the provided relative path + 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"); + } + + /// + public override string ToString() + { + return Info.ToString(); + } + + public void Dispose() + { + foreach (PluginImplementation pluginImplementation in Implementations) + pluginImplementation.Dispose(); + + Kernel?.Dispose(); + PluginLoader?.Dispose(); + } } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/PluginImplementation.cs b/src/Artemis.Core/Plugins/PluginImplementation.cs index 13ad43027..2b3524326 100644 --- a/src/Artemis.Core/Plugins/PluginImplementation.cs +++ b/src/Artemis.Core/Plugins/PluginImplementation.cs @@ -1,27 +1,44 @@ using System; +using System.IO; +using System.Threading; using System.Threading.Tasks; +using Artemis.Storage.Entities.Plugins; +using Stylet; namespace Artemis.Core { /// /// Represents an implementation of a certain type provided by a plugin /// - public abstract class PluginImplementation : IDisposable + public abstract class PluginImplementation : PropertyChangedBase, IDisposable { + private Exception? _loadException; + private bool _isEnabled; + /// /// Gets the plugin that provides this implementation /// - public Plugin Plugin { get; internal set; } - - /// - /// Gets the plugin info related to this plugin - /// - public PluginInfo PluginInfo { get; internal set; } + public Plugin? Plugin { get; internal set; } /// /// Gets whether the plugin is enabled /// - public bool IsEnabled { get; internal set; } + public bool IsEnabled + { + get => _isEnabled; + internal set => SetAndNotify(ref _isEnabled, value); + } + + /// + /// Gets the exception thrown while loading + /// + public Exception? LoadException + { + get => _loadException; + internal set => SetAndNotify(ref _loadException, value); + } + + internal PluginImplementationEntity? Entity { get; set; } /// /// Called when the implementation is activated @@ -35,62 +52,75 @@ namespace Artemis.Core 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 { - if (isAutoEnable && PluginInfo.GetLockFileCreated()) + if (isAutoEnable && GetLockFileCreated()) { // Don't wrap existing lock exceptions, simply rethrow them - if (PluginInfo.LoadException is ArtemisPluginLockException) - throw PluginInfo.LoadException; + if (LoadException is ArtemisPluginLockException) + throw LoadException; - throw new ArtemisPluginLockException(PluginInfo.LoadException); + throw new ArtemisPluginLockException(LoadException); } IsEnabled = true; - PluginInfo.IsEnabled = true; - PluginInfo.CreateLockFile(); + CreateLockFile(); // 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 - // Little meh: Running this from a different thread could cause deadlocks - Task enableTask = Task.Run(InternalEnable); - if (!enableTask.Wait(TimeSpan.FromSeconds(15))) - throw new ArtemisPluginException(PluginInfo, "Plugin load timeout"); + ManualResetEvent wait = new ManualResetEvent(false); + Thread work = new Thread(() => + { + 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(); } // If enable failed, put it back in a disabled state catch (Exception e) { IsEnabled = false; - PluginInfo.IsEnabled = false; - PluginInfo.LoadException = e; + LoadException = e; throw; } finally { - if (!(PluginInfo.LoadException is ArtemisPluginLockException)) - PluginInfo.DeleteLockFile(); + // Clean up the lock file unless the failure was due to the lock file + // 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() @@ -109,6 +139,35 @@ namespace Artemis.Core 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 /// diff --git a/src/Artemis.Core/Plugins/PluginInfo.cs b/src/Artemis.Core/Plugins/PluginInfo.cs index ce0508a9d..def8d63cf 100644 --- a/src/Artemis.Core/Plugins/PluginInfo.cs +++ b/src/Artemis.Core/Plugins/PluginInfo.cs @@ -1,10 +1,5 @@ using System; -using System.IO; -using System.Reflection; -using Artemis.Storage.Entities.Plugins; -using McMaster.NETCore.Plugins; using Newtonsoft.Json; -using Ninject; using Stylet; namespace Artemis.Core @@ -16,14 +11,11 @@ namespace Artemis.Core public class PluginInfo : PropertyChangedBase { private string _description; - private DirectoryInfo _directory; private Guid _guid; private string _icon; - private Plugin _instance; - private bool _isEnabled; - private Exception _loadException; private string _main; private string _name; + private Plugin _plugin; private Version _version; internal PluginInfo() @@ -92,93 +84,19 @@ namespace Artemis.Core internal set => SetAndNotify(ref _main, value); } - /// - /// The plugins root directory - /// - public DirectoryInfo Directory - { - get => _directory; - internal set => SetAndNotify(ref _directory, value); - } - /// /// Gets the plugin this info is associated with /// - public Plugin Instance + public Plugin Plugin { - get => _instance; - internal set => SetAndNotify(ref _instance, value); + get => _plugin; + internal set => SetAndNotify(ref _plugin, value); } - /// - /// Indicates whether the user enabled the plugin or not - /// - public bool IsEnabled - { - get => _isEnabled; - internal set => SetAndNotify(ref _isEnabled, value); - } - - /// - /// Gets the exception thrown while loading - /// - public Exception LoadException - { - get => _loadException; - internal set => SetAndNotify(ref _loadException, value); - } - - /// - /// The assembly the plugin code lives in - /// - public Assembly Assembly { get; internal set; } - - /// - /// The Ninject kernel of the plugin - /// - public IKernel Kernel { get; internal set; } - - /// - /// The PluginLoader backing this plugin - /// - internal PluginLoader PluginLoader { get; set; } - - /// - /// The entity representing the plugin - /// - internal PluginEntity PluginEntity { get; set; } - /// public override string ToString() { 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")); - } } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs b/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs index 9049e48c2..fd9bceea8 100644 --- a/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs +++ b/src/Artemis.Core/Plugins/TimedUpdateRegistration.cs @@ -19,9 +19,9 @@ namespace Artemis.Core Interval = interval; Action = action; - PluginInfo.Instance.Enabled += InstanceOnEnabled; - PluginInfo.Instance.Disabled += InstanceOnDisabled; - if (PluginInfo.Instance.IsEnabled) + PluginInfo.Plugin.Enabled += InstanceOnEnabled; + PluginInfo.Plugin.Disabled += InstanceOnDisabled; + if (PluginInfo.Plugin.IsEnabled) Start(); } @@ -31,9 +31,9 @@ namespace Artemis.Core Interval = interval; AsyncAction = asyncAction; - PluginInfo.Instance.Enabled += InstanceOnEnabled; - PluginInfo.Instance.Disabled += InstanceOnDisabled; - if (PluginInfo.Instance.IsEnabled) + PluginInfo.Plugin.Enabled += InstanceOnEnabled; + PluginInfo.Plugin.Disabled += InstanceOnDisabled; + if (PluginInfo.Plugin.IsEnabled) Start(); } @@ -66,7 +66,7 @@ namespace Artemis.Core { lock (this) { - if (!PluginInfo.Instance.IsEnabled) + if (!PluginInfo.Plugin.IsEnabled) throw new ArtemisPluginException("Cannot start a timed update for a disabled plugin"); if (_timer != null) @@ -99,7 +99,7 @@ namespace Artemis.Core private void TimerOnElapsed(object sender, ElapsedEventArgs e) { - if (!PluginInfo.Instance.IsEnabled) + if (!PluginInfo.Plugin.IsEnabled) return; lock (this) @@ -108,7 +108,7 @@ namespace Artemis.Core _lastEvent = DateTime.Now; // 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; if (Action != null) diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index bc3db3a4e..7189d6b98 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -28,7 +28,7 @@ namespace Artemis.Core.Services private readonly Stopwatch _frameStopWatch; private readonly ILogger _logger; private readonly PluginSetting _loggingLevel; - private readonly IPluginService _pluginService; + private readonly IPluginManagementService _pluginManagementService; private readonly IProfileService _profileService; private readonly IRgbService _rgbService; private readonly ISurfaceService _surfaceService; @@ -36,14 +36,14 @@ namespace Artemis.Core.Services private List _modules; // 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) { Kernel = kernel; Constants.CorePluginInfo.Kernel = kernel; _logger = logger; - _pluginService = pluginService; + _pluginManagementService = pluginManagementService; _rgbService = rgbService; _surfaceService = surfaceService; _profileService = profileService; @@ -57,8 +57,8 @@ namespace Artemis.Core.Services _rgbService.Surface.Updated += SurfaceOnUpdated; _loggingLevel.SettingChanged += (sender, args) => ApplyLoggingLevel(); - _pluginService.PluginEnabled += (sender, args) => UpdatePluginCache(); - _pluginService.PluginDisabled += (sender, args) => UpdatePluginCache(); + _pluginManagementService.PluginEnabled += (sender, args) => UpdatePluginCache(); + _pluginManagementService.PluginDisabled += (sender, args) => UpdatePluginCache(); } public TimeSpan FrameTime { get; private set; } @@ -68,7 +68,7 @@ namespace Artemis.Core.Services public void Dispose() { // Dispose services - _pluginService.Dispose(); + _pluginManagementService.Dispose(); } public bool IsInitialized { get; set; } @@ -85,8 +85,8 @@ namespace Artemis.Core.Services DeserializationLogger.Initialize(Kernel); // Initialize the services - _pluginService.CopyBuiltInPlugins(); - _pluginService.LoadPlugins(StartupArguments.Contains("--ignore-plugin-lock")); + _pluginManagementService.CopyBuiltInPlugins(); + _pluginManagementService.LoadPlugins(StartupArguments.Contains("--ignore-plugin-lock")); ArtemisSurface surfaceConfig = _surfaceService.ActiveSurface; if (surfaceConfig != null) @@ -133,8 +133,8 @@ namespace Artemis.Core.Services private void UpdatePluginCache() { - _modules = _pluginService.GetPluginsOfType().Where(p => p.IsEnabled).ToList(); - _dataModelExpansions = _pluginService.GetPluginsOfType().Where(p => p.IsEnabled).ToList(); + _modules = _pluginManagementService.GetPluginsOfType().Where(p => p.IsEnabled).ToList(); + _dataModelExpansions = _pluginManagementService.GetPluginsOfType().Where(p => p.IsEnabled).ToList(); } private void ConfigureJsonConvert() diff --git a/src/Artemis.Core/Services/Interfaces/IPluginService.cs b/src/Artemis.Core/Services/Interfaces/IPluginService.cs index 4e69711d5..acbb28b61 100644 --- a/src/Artemis.Core/Services/Interfaces/IPluginService.cs +++ b/src/Artemis.Core/Services/Interfaces/IPluginService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Reflection; using RGB.NET.Core; @@ -8,7 +9,7 @@ namespace Artemis.Core.Services /// /// A service providing plugin management /// - public interface IPluginService : IArtemisService, IDisposable + public interface IPluginManagementService : IArtemisService, IDisposable { /// /// Indicates whether or not plugins are currently being loaded @@ -35,7 +36,7 @@ namespace Artemis.Core.Services /// Loads the plugin defined in the provided /// /// The plugin info defining the plugin to load - void LoadPlugin(PluginInfo pluginInfo); + void LoadPlugin(DirectoryInfo pluginInfo); /// /// Unloads the plugin defined in the provided @@ -48,13 +49,13 @@ namespace Artemis.Core.Services /// /// /// If true, fails if there is a lock file present - void EnablePlugin(PluginImplementation pluginImplementation, bool isAutoEnable = false); + void EnablePluginImplementation(PluginImplementation pluginImplementation, bool isAutoEnable = false); /// /// Disables the provided plugin /// /// - void DisablePlugin(PluginImplementation pluginImplementation); + void DisablePluginImplementation(PluginImplementation pluginImplementation); /// /// Finds the plugin info related to the plugin diff --git a/src/Artemis.Core/Services/ModuleService.cs b/src/Artemis.Core/Services/ModuleService.cs index 499f10e3c..a08e06119 100644 --- a/src/Artemis.Core/Services/ModuleService.cs +++ b/src/Artemis.Core/Services/ModuleService.cs @@ -17,22 +17,22 @@ namespace Artemis.Core.Services private static readonly SemaphoreSlim ActiveModuleSemaphore = new SemaphoreSlim(1, 1); private readonly ILogger _logger; private readonly IModuleRepository _moduleRepository; - private readonly IPluginService _pluginService; + private readonly IPluginManagementService _pluginManagementService; 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; _moduleRepository = moduleRepository; - _pluginService = pluginService; + _pluginManagementService = pluginManagementService; _profileService = profileService; - _pluginService.PluginEnabled += PluginServiceOnPluginEnabled; + _pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementEnabled; Timer activationUpdateTimer = new Timer(2000); activationUpdateTimer.Start(); activationUpdateTimer.Elapsed += ActivationUpdateTimerOnElapsed; - foreach (Module module in _pluginService.GetPluginsOfType()) + foreach (Module module in _pluginManagementService.GetPluginsOfType()) InitialiseOrApplyPriority(module); } @@ -56,7 +56,7 @@ namespace Artemis.Core.Services _logger.Information("Clearing active module override"); // Always deactivate all other modules whenever override is called - List modules = _pluginService.GetPluginsOfType().ToList(); + List modules = _pluginManagementService.GetPluginsOfType().ToList(); foreach (Module module in modules.Where(m => m != overrideModule)) OverrideDeactivate(module, overrideModule != null); @@ -97,7 +97,7 @@ namespace Artemis.Core.Services Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); - List modules = _pluginService.GetPluginsOfType().ToList(); + List modules = _pluginManagementService.GetPluginsOfType().ToList(); List tasks = new List(); foreach (Module module in modules) { @@ -128,7 +128,7 @@ namespace Artemis.Core.Services if (module.PriorityCategory == category && module.Priority == priority) return; - List modules = _pluginService.GetPluginsOfType().Where(m => m.PriorityCategory == category).OrderBy(m => m.Priority).ToList(); + List modules = _pluginManagementService.GetPluginsOfType().Where(m => m.PriorityCategory == category).OrderBy(m => m.Priority).ToList(); if (modules.Contains(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); } diff --git a/src/Artemis.Core/Services/PluginService.cs b/src/Artemis.Core/Services/PluginService.cs index e1b81ff14..17b511c51 100644 --- a/src/Artemis.Core/Services/PluginService.cs +++ b/src/Artemis.Core/Services/PluginService.cs @@ -22,19 +22,19 @@ namespace Artemis.Core.Services /// /// Provides access to plugin loading and unloading /// - internal class PluginService : IPluginService + internal class PluginManagementService : IPluginManagementService { private readonly IKernel _kernel; private readonly ILogger _logger; private readonly IPluginRepository _pluginRepository; - private readonly List _plugins; + private readonly List _plugins; - public PluginService(IKernel kernel, ILogger logger, IPluginRepository pluginRepository) + public PluginManagementService(IKernel kernel, ILogger logger, IPluginRepository pluginRepository) { _kernel = kernel; _logger = logger; _pluginRepository = pluginRepository; - _plugins = new List(); + _plugins = new List(); // Ensure the plugins directory exists if (!Directory.Exists(Constants.DataFolder + "plugins")) @@ -43,6 +43,8 @@ namespace Artemis.Core.Services public bool LoadingPlugins { get; private set; } + #region Built in plugins + public void CopyBuiltInPlugins() { OnCopyingBuildInPlugins(); @@ -101,6 +103,10 @@ namespace Artemis.Core.Services } } + #endregion + + #region Plugins + public void LoadPlugins(bool ignorePluginLock) { if (LoadingPlugins) @@ -119,15 +125,7 @@ namespace Artemis.Core.Services { try { - // Load the metadata - 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(File.ReadAllText(metadataFile)); - pluginInfo.Directory = subDirectory; - - LoadPlugin(pluginInfo); + LoadPlugin(subDirectory); } catch (Exception e) { @@ -136,15 +134,18 @@ namespace Artemis.Core.Services } // 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); - } - catch (Exception) - { - // ignored, logged in EnablePlugin + try + { + EnablePluginImplementation(pluginImplementation, !ignorePluginLock); + } + 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) { - _logger.Debug("Loading plugin {pluginInfo}", pluginInfo); - OnPluginLoading(new PluginEventArgs(pluginInfo)); + _logger.Debug("Loading plugin from {directory}", pluginDirectory.FullName); - // Unload the plugin first if it is already loaded - if (_plugins.Contains(pluginInfo)) - UnloadPlugin(pluginInfo); + // Load the metadata + string metadataFile = Path.Combine(pluginDirectory.FullName, "plugin.json"); + 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); - if (pluginEntity == null) - pluginEntity = new PluginEntity {Id = pluginInfo.Guid, IsEnabled = true}; + // PluginInfo contains the ID which we need to move on + PluginInfo pluginInfo = JsonConvert.DeserializeObject(File.ReadAllText(metadataFile)); - pluginInfo.PluginEntity = pluginEntity; - pluginInfo.IsEnabled = pluginEntity.IsEnabled; + // Ensure the plugin is not already loaded + 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)) - 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 - pluginInfo.PluginLoader = PluginLoader.CreateFromAssemblyFile(mainFile, configure => + plugin.PluginLoader = PluginLoader.CreateFromAssemblyFile(mainFile!, configure => { configure.IsUnloadable = true; configure.PreferSharedTypes = true; @@ -195,57 +203,58 @@ namespace Artemis.Core.Services try { - pluginInfo.Assembly = pluginInfo.PluginLoader.LoadDefaultAssembly(); + plugin.Assembly = plugin.PluginLoader.LoadDefaultAssembly(); } 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 - List pluginTypes; + List implementationTypes; 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) { - 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) - throw new ArtemisPluginException(pluginInfo, $"Plugin contains {pluginTypes.Count} implementations of Plugin, only 1 allowed"); - if (pluginTypes.Count == 0) - throw new ArtemisPluginException(pluginInfo, "Plugin contains no implementation of Plugin"); + // Create the Ninject child kernel and load the module + plugin.Kernel = new ChildKernel(_kernel); + plugin.Kernel.Load(new PluginModule(pluginInfo)); - Type pluginType = pluginTypes.Single(); - try + if (!implementationTypes.Any()) + _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 = { - new Parameter("PluginInfo", pluginInfo, false) - }; - pluginInfo.Kernel = new ChildKernel(_kernel); - pluginInfo.Kernel.Load(new PluginModule(pluginInfo)); - pluginInfo.Instance = (PluginImplementation) pluginInfo.Kernel.Get(pluginType, constraint: null, parameters: parameters); - pluginInfo.Instance.PluginInfo = pluginInfo; - } - catch (Exception e) - { - throw new ArtemisPluginException(pluginInfo, "Failed to instantiate the plugin", e); + try + { + PluginImplementation instance = (PluginImplementation)plugin.Kernel.Get(implementationType); + plugin.AddImplementation(instance); + } + catch (Exception e) + { + throw new ArtemisPluginException(plugin, "Failed to load instantiate implementation", e); + } } - _plugins.Add(pluginInfo); - OnPluginLoaded(new PluginEventArgs(pluginInfo)); + _plugins.Add(plugin); + OnPluginLoaded(new PluginEventArgs(plugin)); } } - public void UnloadPlugin(PluginInfo pluginInfo) + public void UnloadPlugin(Plugin plugin) { lock (_plugins) { try { - pluginInfo.Instance.SetEnabled(false); + plugin.SetEnabled(false); } catch (Exception) { @@ -253,23 +262,24 @@ namespace Artemis.Core.Services } finally { - OnPluginDisabled(new PluginEventArgs(pluginInfo)); + OnPluginDisabled(new PluginEventArgs(plugin)); } - pluginInfo.Instance.Dispose(); - pluginInfo.PluginLoader.Dispose(); - pluginInfo.Kernel.Dispose(); + plugin.Dispose(); + _plugins.Remove(plugin); - _plugins.Remove(pluginInfo); - - OnPluginUnloaded(new PluginEventArgs(pluginInfo)); + OnPluginUnloaded(new PluginEventArgs(plugin)); } } - 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); - OnPluginEnabling(new PluginEventArgs(pluginImplementation.PluginInfo)); + _logger.Debug("Enabling plugin implementation {implementation} - {plugin}", pluginImplementation, pluginImplementation.Plugin); 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) { @@ -335,9 +345,12 @@ namespace Artemis.Core.Services OnPluginDisabled(new PluginEventArgs(pluginImplementation.PluginInfo)); } + #endregion + + public PluginInfo GetPluginInfo(PluginImplementation pluginImplementation) { - return _plugins.FirstOrDefault(p => p.Instance == pluginImplementation); + return _plugins.FirstOrDefault(p => p.Plugin == pluginImplementation); } public List GetAllPluginInfo() @@ -347,12 +360,12 @@ namespace Artemis.Core.Services public List GetPluginsOfType() 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) { - return _plugins.FirstOrDefault(p => p.Assembly == assembly)?.Instance; + return _plugins.FirstOrDefault(p => p.Assembly == assembly)?.Plugin; } public PluginImplementation GetPluginByDevice(IRGBDevice rgbDevice) @@ -362,8 +375,8 @@ namespace Artemis.Core.Services public PluginImplementation GetCallingPlugin() { - StackTrace stackTrace = new StackTrace(); // get call stack - StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) + StackTrace stackTrace = new StackTrace(); // get call stack + StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) foreach (StackFrame stackFrame in stackFrames) { @@ -395,7 +408,7 @@ namespace Artemis.Core.Services if (createLockFile) File.Create(Path.Combine(pluginDirectory.FullName, "artemis.lock")).Close(); } - + #region Events public event EventHandler CopyingBuildInPlugins; @@ -406,6 +419,9 @@ namespace Artemis.Core.Services public event EventHandler PluginEnabled; public event EventHandler PluginDisabled; + public event EventHandler PluginImplementationEnabled; + public event EventHandler PluginImplementationDisabled; + protected virtual void OnCopyingBuildInPlugins() { CopyingBuildInPlugins?.Invoke(this, EventArgs.Empty); @@ -441,6 +457,16 @@ namespace Artemis.Core.Services 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 } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/Registration/DataModelService.cs b/src/Artemis.Core/Services/Registration/DataModelService.cs index e5f6c71f1..acfb0f1bf 100644 --- a/src/Artemis.Core/Services/Registration/DataModelService.cs +++ b/src/Artemis.Core/Services/Registration/DataModelService.cs @@ -8,16 +8,16 @@ namespace Artemis.Core.Services { internal class DataModelService : IDataModelService { - public DataModelService(IPluginService pluginService) + public DataModelService(IPluginManagementService pluginManagementService) { // Add data models of already loaded plugins - foreach (Module module in pluginService.GetPluginsOfType().Where(p => p.IsEnabled)) + foreach (Module module in pluginManagementService.GetPluginsOfType().Where(p => p.IsEnabled)) AddModuleDataModel(module); - foreach (BaseDataModelExpansion dataModelExpansion in pluginService.GetPluginsOfType().Where(p => p.IsEnabled)) + foreach (BaseDataModelExpansion dataModelExpansion in pluginManagementService.GetPluginsOfType().Where(p => p.IsEnabled)) AddDataModelExpansionDataModel(dataModelExpansion); // Add data models of new plugins when they get enabled - pluginService.PluginEnabled += PluginServiceOnPluginEnabled; + pluginManagementService.PluginEnabled += PluginServiceOnPluginEnabled; } public DataModelRegistration RegisterDataModel(DataModel dataModel) @@ -56,9 +56,9 @@ namespace Artemis.Core.Services private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e) { - if (e.PluginInfo.Instance is Module module) + if (e.PluginInfo.Plugin is Module module) AddModuleDataModel(module); - else if (e.PluginInfo.Instance is BaseDataModelExpansion dataModelExpansion) + else if (e.PluginInfo.Plugin is BaseDataModelExpansion dataModelExpansion) AddDataModelExpansionDataModel(dataModelExpansion); } diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs index 880ff1ab1..469526f73 100644 --- a/src/Artemis.Core/Services/Storage/ProfileService.cs +++ b/src/Artemis.Core/Services/Storage/ProfileService.cs @@ -13,19 +13,19 @@ namespace Artemis.Core.Services internal class ProfileService : IProfileService { private readonly ILogger _logger; - private readonly IPluginService _pluginService; + private readonly IPluginManagementService _pluginManagementService; private readonly IProfileRepository _profileRepository; private readonly ISurfaceService _surfaceService; internal ProfileService(ILogger logger, - IPluginService pluginService, + IPluginManagementService pluginManagementService, ISurfaceService surfaceService, IConditionOperatorService conditionOperatorService, IDataBindingService dataBindingService, IProfileRepository profileRepository) { _logger = logger; - _pluginService = pluginService; + _pluginManagementService = pluginManagementService; _surfaceService = surfaceService; _profileRepository = profileRepository; @@ -118,15 +118,15 @@ namespace Artemis.Core.Services } // This could happen during activation so subscribe to it - _pluginService.PluginEnabled += ActivatingProfilePluginToggle; - _pluginService.PluginDisabled += ActivatingProfilePluginToggle; + _pluginManagementService.PluginEnabled += ActivatingProfilePluginToggle; + _pluginManagementService.PluginDisabled += ActivatingProfilePluginToggle; _surfaceService.SurfaceConfigurationUpdated += ActivatingProfileSurfaceUpdate; await profileDescriptor.ProfileModule.ChangeActiveProfileAnimated(profile, _surfaceService.ActiveSurface); SaveActiveProfile(profileDescriptor.ProfileModule); - _pluginService.PluginEnabled -= ActivatingProfilePluginToggle; - _pluginService.PluginDisabled -= ActivatingProfilePluginToggle; + _pluginManagementService.PluginEnabled -= ActivatingProfilePluginToggle; + _pluginManagementService.PluginDisabled -= ActivatingProfilePluginToggle; _surfaceService.SurfaceConfigurationUpdated -= ActivatingProfileSurfaceUpdate; return profile; @@ -285,7 +285,7 @@ namespace Artemis.Core.Services /// private void ActiveProfilesPopulateLeds(ArtemisSurface surface) { - List profileModules = _pluginService.GetPluginsOfType(); + List profileModules = _pluginManagementService.GetPluginsOfType(); foreach (ProfileModule profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList()) profileModule.ActiveProfile.PopulateLeds(surface); } diff --git a/src/Artemis.Core/Services/Storage/SurfaceService.cs b/src/Artemis.Core/Services/Storage/SurfaceService.cs index 44a2d8b0a..24265e06e 100644 --- a/src/Artemis.Core/Services/Storage/SurfaceService.cs +++ b/src/Artemis.Core/Services/Storage/SurfaceService.cs @@ -12,18 +12,18 @@ namespace Artemis.Core.Services internal class SurfaceService : ISurfaceService { private readonly ILogger _logger; - private readonly IPluginService _pluginService; + private readonly IPluginManagementService _pluginManagementService; private readonly PluginSetting _renderScaleSetting; private readonly IRgbService _rgbService; private readonly List _surfaceConfigurations; 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; _surfaceRepository = surfaceRepository; _rgbService = rgbService; - _pluginService = pluginService; + _pluginManagementService = pluginManagementService; _surfaceConfigurations = new List(); _renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 0.5); @@ -44,7 +44,7 @@ namespace Artemis.Core.Services // Add all current devices foreach (IRGBDevice rgbDevice in _rgbService.LoadedDevices) { - PluginImplementation pluginImplementation = _pluginService.GetPluginByDevice(rgbDevice); + PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(rgbDevice); 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); if (device != null) { - PluginImplementation pluginImplementation = _pluginService.GetPluginByDevice(device); + PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(device); 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); if (existingDeviceConfig != null) { - PluginImplementation pluginImplementation = _pluginService.GetPluginByDevice(rgbDevice); + PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(rgbDevice); device = new ArtemisDevice(rgbDevice, pluginImplementation, surface, existingDeviceConfig); } // Fall back on creating a new device @@ -189,7 +189,7 @@ namespace Artemis.Core.Services rgbDevice.DeviceInfo, deviceIdentifier ); - PluginImplementation pluginImplementation = _pluginService.GetPluginByDevice(rgbDevice); + PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(rgbDevice); device = new ArtemisDevice(rgbDevice, pluginImplementation, surface); } diff --git a/src/Artemis.Core/Stores/ConditionOperatorStore.cs b/src/Artemis.Core/Stores/ConditionOperatorStore.cs index 01096d82a..0873bafa9 100644 --- a/src/Artemis.Core/Stores/ConditionOperatorStore.cs +++ b/src/Artemis.Core/Stores/ConditionOperatorStore.cs @@ -16,7 +16,7 @@ namespace Artemis.Core if (Registrations.Any(r => r.ConditionOperator == conditionOperator)) 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); } diff --git a/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs b/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs index dadab83c1..bb83a7aef 100644 --- a/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs +++ b/src/Artemis.Core/Stores/DataBindingModifierTypeStore.cs @@ -16,7 +16,7 @@ namespace Artemis.Core if (Registrations.Any(r => r.DataBindingModifierType == modifierType)) 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); } diff --git a/src/Artemis.Core/Stores/LayerBrushStore.cs b/src/Artemis.Core/Stores/LayerBrushStore.cs index 2db50e18f..3d5c59c96 100644 --- a/src/Artemis.Core/Stores/LayerBrushStore.cs +++ b/src/Artemis.Core/Stores/LayerBrushStore.cs @@ -17,7 +17,7 @@ namespace Artemis.Core if (Registrations.Any(r => r.LayerBrushDescriptor == descriptor)) 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); } diff --git a/src/Artemis.Core/Stores/LayerEffectStore.cs b/src/Artemis.Core/Stores/LayerEffectStore.cs index 1e5f1ebd1..420edb464 100644 --- a/src/Artemis.Core/Stores/LayerEffectStore.cs +++ b/src/Artemis.Core/Stores/LayerEffectStore.cs @@ -17,7 +17,7 @@ namespace Artemis.Core if (Registrations.Any(r => r.LayerEffectDescriptor == descriptor)) 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); } diff --git a/src/Artemis.Core/Utilities/CorePluginImplementation.cs b/src/Artemis.Core/Utilities/CorePluginImplementation.cs index 23ab55156..f7a5d4310 100644 --- a/src/Artemis.Core/Utilities/CorePluginImplementation.cs +++ b/src/Artemis.Core/Utilities/CorePluginImplementation.cs @@ -9,7 +9,7 @@ namespace Artemis.Core { public CorePluginImplementation() { - Constants.CorePluginInfo.Instance = this; + Constants.CorePluginInfo.Plugin = this; IsEnabled = true; } diff --git a/src/Artemis.Storage/Entities/Plugins/PluginEntity.cs b/src/Artemis.Storage/Entities/Plugins/PluginEntity.cs index 65b84733f..3cfa1088e 100644 --- a/src/Artemis.Storage/Entities/Plugins/PluginEntity.cs +++ b/src/Artemis.Storage/Entities/Plugins/PluginEntity.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace Artemis.Storage.Entities.Plugins { @@ -9,5 +10,16 @@ namespace Artemis.Storage.Entities.Plugins { public Guid Id { get; set; } public bool IsEnabled { get; set; } + + public List Implementations { get; set; } + } + + /// + /// Represents the configuration of a plugin implementation, each implementation has one configuration + /// + public class PluginImplementationEntity + { + public string Type { get; set; } + public bool IsEnabled { get; set; } } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/DataModelVisualization/DataModelVisualizationRegistration.cs b/src/Artemis.UI.Shared/DataModelVisualization/DataModelVisualizationRegistration.cs index a7a313c17..e3a66bc8a 100644 --- a/src/Artemis.UI.Shared/DataModelVisualization/DataModelVisualizationRegistration.cs +++ b/src/Artemis.UI.Shared/DataModelVisualization/DataModelVisualizationRegistration.cs @@ -22,7 +22,7 @@ namespace Artemis.UI.Shared ViewModelType = viewModelType; if (PluginInfo != Constants.CorePluginInfo) - PluginInfo.Instance.Disabled += InstanceOnDisabled; + PluginInfo.Plugin.Disabled += InstanceOnDisabled; } public RegistrationType RegistrationType { get; } @@ -35,7 +35,7 @@ namespace Artemis.UI.Shared internal void Unsubscribe() { if (PluginInfo != Constants.CorePluginInfo) - PluginInfo.Instance.Disabled -= InstanceOnDisabled; + PluginInfo.Plugin.Disabled -= InstanceOnDisabled; } private void InstanceOnDisabled(object sender, EventArgs e) diff --git a/src/Artemis.UI.Shared/PropertyInput/PropertyInputRegistration.cs b/src/Artemis.UI.Shared/PropertyInput/PropertyInputRegistration.cs index f646f6f92..cebb27fcc 100644 --- a/src/Artemis.UI.Shared/PropertyInput/PropertyInputRegistration.cs +++ b/src/Artemis.UI.Shared/PropertyInput/PropertyInputRegistration.cs @@ -16,7 +16,7 @@ namespace Artemis.UI.Shared ViewModelType = viewModelType; if (PluginInfo != Constants.CorePluginInfo) - PluginInfo.Instance.Disabled += InstanceOnDisabled; + PluginInfo.Plugin.Disabled += InstanceOnDisabled; } public PluginInfo PluginInfo { get; } @@ -26,7 +26,7 @@ namespace Artemis.UI.Shared internal void Unsubscribe() { if (PluginInfo != Constants.CorePluginInfo) - PluginInfo.Instance.Disabled -= InstanceOnDisabled; + PluginInfo.Plugin.Disabled -= InstanceOnDisabled; } private void InstanceOnDisabled(object sender, EventArgs e) diff --git a/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs b/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs index 1eba9a48f..25066daff 100644 --- a/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs +++ b/src/Artemis.UI.Shared/Services/Dialog/DialogService.cs @@ -22,14 +22,14 @@ namespace Artemis.UI.Shared.Services private readonly IKernel _kernel; private readonly IViewManager _viewManager; 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; _viewManager = viewManager; _windowManager = windowManager; - _pluginService = pluginService; + _pluginManagementService = pluginManagementService; } private async Task ShowDialog(IParameter[] parameters) where T : DialogViewModelBase @@ -109,7 +109,7 @@ namespace Artemis.UI.Shared.Services private async Task ShowDialogAt(string identifier, IParameter[] parameters) where T : DialogViewModelBase { - PluginImplementation callingPluginImplementation = _pluginService.GetCallingPlugin(); + PluginImplementation callingPluginImplementation = _pluginManagementService.GetCallingPlugin(); if (parameters == null) throw new ArgumentNullException(nameof(parameters)); if (callingPluginImplementation != null) diff --git a/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs b/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs index 33270c15a..a7a3b0e53 100644 --- a/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs +++ b/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs @@ -11,17 +11,17 @@ namespace Artemis.UI.PropertyInput { public class BrushPropertyInputViewModel : PropertyInputViewModel { - private readonly IPluginService _pluginService; + private readonly IPluginManagementService _pluginManagementService; private BindableCollection _descriptors; public BrushPropertyInputViewModel(LayerProperty layerProperty, IProfileEditorService profileEditorService, - IPluginService pluginService) : base(layerProperty, profileEditorService) + IPluginManagementService pluginManagementService) : base(layerProperty, profileEditorService) { - _pluginService = pluginService; + _pluginManagementService = pluginManagementService; - _pluginService.PluginEnabled += PluginServiceOnPluginLoaded; - _pluginService.PluginDisabled += PluginServiceOnPluginLoaded; + _pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementLoaded; + _pluginManagementService.PluginDisabled += PluginManagementServiceOnPluginManagementLoaded; UpdateEnumValues(); } @@ -39,7 +39,7 @@ namespace Artemis.UI.PropertyInput public void UpdateEnumValues() { - List layerBrushProviders = _pluginService.GetPluginsOfType(); + List layerBrushProviders = _pluginManagementService.GetPluginsOfType(); Descriptors = new BindableCollection(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors)); NotifyOfPropertyChange(nameof(SelectedDescriptor)); } @@ -47,8 +47,8 @@ namespace Artemis.UI.PropertyInput public override void Dispose() { - _pluginService.PluginEnabled -= PluginServiceOnPluginLoaded; - _pluginService.PluginDisabled -= PluginServiceOnPluginLoaded; + _pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginManagementLoaded; + _pluginManagementService.PluginDisabled -= PluginManagementServiceOnPluginManagementLoaded; base.Dispose(); } @@ -63,7 +63,7 @@ namespace Artemis.UI.PropertyInput InputValue = new LayerBrushReference(value); } - private void PluginServiceOnPluginLoaded(object sender, PluginEventArgs e) + private void PluginManagementServiceOnPluginManagementLoaded(object sender, PluginEventArgs e) { UpdateEnumValues(); } diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerEffects/EffectsViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerEffects/EffectsViewModel.cs index 1abc15d2c..8ab195a6f 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerEffects/EffectsViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerEffects/EffectsViewModel.cs @@ -12,13 +12,13 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.LayerEffects { public class EffectsViewModel : Conductor.Collection.AllActive { - private readonly IPluginService _pluginService; + private readonly IPluginManagementService _pluginManagementService; private readonly IProfileEditorService _profileEditorService; 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; LayerPropertiesViewModel = layerPropertiesViewModel; PropertyChanged += HandleSelectedLayerEffectChanged; @@ -35,7 +35,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.LayerEffects public void PopulateDescriptors() { - List layerBrushProviders = _pluginService.GetPluginsOfType(); + List layerBrushProviders = _pluginManagementService.GetPluginsOfType(); List descriptors = layerBrushProviders.SelectMany(l => l.LayerEffectDescriptors).ToList(); Items.AddRange(descriptors.Except(Items)); Items.RemoveRange(Items.Except(descriptors)); diff --git a/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs b/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs index 470c4d66d..2bd2a2b79 100644 --- a/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Debug/Tabs/DataModelDebugViewModel.cs @@ -13,7 +13,7 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs public class DataModelDebugViewModel : Screen { private readonly IDataModelUIService _dataModelUIService; - private readonly IPluginService _pluginService; + private readonly IPluginManagementService _pluginManagementService; private readonly Timer _updateTimer; private bool _isModuleFilterEnabled; private DataModelPropertiesViewModel _mainDataModel; @@ -21,10 +21,10 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs private string _propertySearch; private Module _selectedModule; - public DataModelDebugViewModel(IDataModelUIService dataModelUIService, IPluginService pluginService) + public DataModelDebugViewModel(IDataModelUIService dataModelUIService, IPluginManagementService pluginManagementService) { _dataModelUIService = dataModelUIService; - _pluginService = pluginService; + _pluginManagementService = pluginManagementService; _updateTimer = new Timer(500); DisplayName = "Data model"; @@ -77,8 +77,8 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs GetDataModel(); _updateTimer.Start(); _updateTimer.Elapsed += OnUpdateTimerOnElapsed; - _pluginService.PluginEnabled += PluginServiceOnPluginToggled; - _pluginService.PluginDisabled += PluginServiceOnPluginToggled; + _pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementToggled; + _pluginManagementService.PluginDisabled += PluginManagementServiceOnPluginManagementToggled; PopulateModules(); @@ -89,8 +89,8 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs { _updateTimer.Stop(); _updateTimer.Elapsed -= OnUpdateTimerOnElapsed; - _pluginService.PluginEnabled -= PluginServiceOnPluginToggled; - _pluginService.PluginDisabled -= PluginServiceOnPluginToggled; + _pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginManagementToggled; + _pluginManagementService.PluginDisabled -= PluginManagementServiceOnPluginManagementToggled; base.OnDeactivate(); } @@ -110,14 +110,14 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs : _dataModelUIService.GetMainDataModelVisualization(); } - private void PluginServiceOnPluginToggled(object? sender, PluginEventArgs e) + private void PluginManagementServiceOnPluginManagementToggled(object? sender, PluginEventArgs e) { PopulateModules(); } private void PopulateModules() { - Modules = _pluginService.GetPluginsOfType().Where(p => p.IsEnabled).ToList(); + Modules = _pluginManagementService.GetPluginsOfType().Where(p => p.IsEnabled).ToList(); } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs index 5760fd78f..d9d405546 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/General/GeneralSettingsTabViewModel.cs @@ -25,7 +25,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.General private List> _targetFrameRates; private readonly PluginSetting _defaultLayerBrushDescriptor; - public GeneralSettingsTabViewModel(IDialogService dialogService, IDebugService debugService, ISettingsService settingsService, IPluginService pluginService) + public GeneralSettingsTabViewModel(IDialogService dialogService, IDebugService debugService, ISettingsService settingsService, IPluginManagementService pluginManagementService) { DisplayName = "GENERAL"; @@ -46,7 +46,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.General // Anything else is kinda broken right now SampleSizes = new List {1, 9}; - List layerBrushProviders = pluginService.GetPluginsOfType(); + List layerBrushProviders = pluginManagementService.GetPluginsOfType(); LayerBrushDescriptors = new BindableCollection(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors)); _defaultLayerBrushDescriptor = _settingsService.GetSetting("ProfileEditor.DefaultLayerBrushDescriptor", new LayerBrushReference diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Modules/ModuleOrderTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Modules/ModuleOrderTabViewModel.cs index 7e1452e6d..a0e92df46 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Modules/ModuleOrderTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Modules/ModuleOrderTabViewModel.cs @@ -10,17 +10,17 @@ namespace Artemis.UI.Screens.Settings.Tabs.Modules public class ModuleOrderTabViewModel : Screen, IDropTarget { private readonly IModuleService _moduleService; - private readonly IPluginService _pluginService; + private readonly IPluginManagementService _pluginManagementService; private readonly DefaultDropHandler _defaultDropHandler; private readonly List _modules; - public ModuleOrderTabViewModel(IPluginService pluginService, IModuleService moduleService) + public ModuleOrderTabViewModel(IPluginManagementService pluginManagementService, IModuleService moduleService) { DisplayName = "MODULE PRIORITY"; - _pluginService = pluginService; + _pluginManagementService = pluginManagementService; _moduleService = moduleService; - _modules = new List(pluginService.GetPluginsOfType().Select(m => new ModuleOrderModuleViewModel(m))); + _modules = new List(pluginManagementService.GetPluginsOfType().Select(m => new ModuleOrderModuleViewModel(m))); _defaultDropHandler = new DefaultDropHandler(); NormalModules = new BindableCollection(); diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs index 9693c7d51..82488df16 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs @@ -9,15 +9,15 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins { public class PluginSettingsTabViewModel : Conductor.Collection.AllActive { - private readonly IPluginService _pluginService; + private readonly IPluginManagementService _pluginManagementService; private readonly ISettingsVmFactory _settingsVmFactory; private BindableCollection _plugins; - public PluginSettingsTabViewModel(IPluginService pluginService, ISettingsVmFactory settingsVmFactory) + public PluginSettingsTabViewModel(IPluginManagementService pluginManagementService, ISettingsVmFactory settingsVmFactory) { DisplayName = "PLUGINS"; - _pluginService = pluginService; + _pluginManagementService = pluginManagementService; _settingsVmFactory = settingsVmFactory; } @@ -29,7 +29,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins Items.Clear(); await Task.Delay(200); - List instances = _pluginService.GetAllPluginInfo().Select(p => _settingsVmFactory.CreatePluginSettingsViewModel(p.Instance)).ToList(); + List instances = _pluginManagementService.GetAllPluginInfo().Select(p => _settingsVmFactory.CreatePluginSettingsViewModel(p.Plugin)).ToList(); foreach (PluginSettingsViewModel pluginSettingsViewModel in instances) Items.Add(pluginSettingsViewModel); }); diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs index a461cb501..69f9076da 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs @@ -26,7 +26,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins { private readonly IDialogService _dialogService; private readonly ILogger _logger; - private readonly IPluginService _pluginService; + private readonly IPluginManagementService _pluginManagementService; private readonly ISnackbarMessageQueue _snackbarMessageQueue; private readonly IWindowManager _windowManager; private bool _enabling; @@ -37,7 +37,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins ILogger logger, IWindowManager windowManager, IDialogService dialogService, - IPluginService pluginService, + IPluginManagementService pluginManagementService, ISnackbarMessageQueue snackbarMessageQueue) { PluginImplementation = pluginImplementation; @@ -46,7 +46,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins _logger = logger; _windowManager = windowManager; _dialogService = dialogService; - _pluginService = pluginService; + _pluginManagementService = pluginManagementService; _snackbarMessageQueue = snackbarMessageQueue; } @@ -183,7 +183,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins try { - _pluginService.EnablePlugin(PluginImplementation); + _pluginManagementService.EnablePluginImplementation(PluginImplementation); } catch (Exception e) { @@ -195,7 +195,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins } } else - _pluginService.DisablePlugin(PluginImplementation); + _pluginManagementService.DisablePluginImplementation(PluginImplementation); NotifyOfPropertyChange(nameof(IsEnabled)); NotifyOfPropertyChange(nameof(CanOpenSettings)); @@ -208,7 +208,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins bool restart = false; // 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 (!restartQueued && PluginImplementation.IsEnabled) { @@ -220,7 +220,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins ); } - _pluginService.DisablePlugin(PluginImplementation); + _pluginManagementService.DisablePluginImplementation(PluginImplementation); if (restart) { _logger.Debug("Restarting for device provider disable {pluginInfo}", PluginImplementation.PluginInfo); diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs index 9b4577cb8..6b77f99bf 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs @@ -29,18 +29,18 @@ namespace Artemis.UI.Screens.Sidebar private readonly Timer _activeModulesUpdateTimer; private readonly IKernel _kernel; private readonly IModuleVmFactory _moduleVmFactory; - private readonly IPluginService _pluginService; + private readonly IPluginManagementService _pluginManagementService; private string _activeModules; private bool _isSidebarOpen; private IScreen _selectedItem; private BindableCollection _sidebarItems; private Dictionary _sidebarModules; - public SidebarViewModel(IKernel kernel, IEventAggregator eventAggregator, IModuleVmFactory moduleVmFactory, IPluginService pluginService) + public SidebarViewModel(IKernel kernel, IEventAggregator eventAggregator, IModuleVmFactory moduleVmFactory, IPluginManagementService pluginManagementService) { _kernel = kernel; _moduleVmFactory = moduleVmFactory; - _pluginService = pluginService; + _pluginManagementService = pluginManagementService; SidebarModules = new Dictionary(); SidebarItems = new BindableCollection(); @@ -49,8 +49,8 @@ namespace Artemis.UI.Screens.Sidebar _activeModulesUpdateTimer.Start(); _activeModulesUpdateTimer.Elapsed += ActiveModulesUpdateTimerOnElapsed; - _pluginService.PluginEnabled += PluginServiceOnPluginEnabled; - _pluginService.PluginDisabled += PluginServiceOnPluginDisabled; + _pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementEnabled; + _pluginManagementService.PluginDisabled += PluginManagementServiceOnPluginManagementDisabled; SetupSidebar(); eventAggregator.Subscribe(this); @@ -96,8 +96,8 @@ namespace Artemis.UI.Screens.Sidebar SelectedItem?.Deactivate(); SelectedItem = null; - _pluginService.PluginEnabled -= PluginServiceOnPluginEnabled; - _pluginService.PluginDisabled -= PluginServiceOnPluginDisabled; + _pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginManagementEnabled; + _pluginManagementService.PluginDisabled -= PluginManagementServiceOnPluginManagementDisabled; _activeModulesUpdateTimer.Stop(); _activeModulesUpdateTimer.Elapsed -= ActiveModulesUpdateTimerOnElapsed; @@ -118,7 +118,7 @@ namespace Artemis.UI.Screens.Sidebar // Add all activated modules SidebarItems.Add(new DividerNavigationItem()); SidebarItems.Add(new SubheaderNavigationItem {Subheader = "Modules"}); - List modules = _pluginService.GetPluginsOfType().ToList(); + List modules = _pluginManagementService.GetPluginsOfType().ToList(); foreach (Module module in modules) AddModule(module); @@ -210,15 +210,15 @@ namespace Artemis.UI.Screens.Sidebar #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); } - 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); } diff --git a/src/Artemis.UI/Screens/Splash/SplashViewModel.cs b/src/Artemis.UI/Screens/Splash/SplashViewModel.cs index 33e205a25..e4fc1c2a4 100644 --- a/src/Artemis.UI/Screens/Splash/SplashViewModel.cs +++ b/src/Artemis.UI/Screens/Splash/SplashViewModel.cs @@ -10,13 +10,13 @@ namespace Artemis.UI.Screens.Splash public class SplashViewModel : Screen { private readonly ICoreService _coreService; - private readonly IPluginService _pluginService; + private readonly IPluginManagementService _pluginManagementService; private string _status; - public SplashViewModel(ICoreService coreService, IPluginService pluginService) + public SplashViewModel(ICoreService coreService, IPluginManagementService pluginManagementService) { _coreService = coreService; - _pluginService = pluginService; + _pluginManagementService = pluginManagementService; Status = "Initializing Core"; } @@ -37,46 +37,46 @@ namespace Artemis.UI.Screens.Splash protected override void OnInitialActivate() { _coreService.Initialized += OnCoreServiceOnInitialized; - _pluginService.CopyingBuildInPlugins += OnPluginServiceOnCopyingBuildInPlugins; - _pluginService.PluginLoading += OnPluginServiceOnPluginLoading; - _pluginService.PluginLoaded += OnPluginServiceOnPluginLoaded; - _pluginService.PluginEnabling += PluginServiceOnPluginEnabling; - _pluginService.PluginEnabled += PluginServiceOnPluginEnabled; + _pluginManagementService.CopyingBuildInPlugins += OnPluginManagementServiceOnCopyingBuildInPluginsManagement; + _pluginManagementService.PluginLoading += OnPluginManagementServiceOnPluginManagementLoading; + _pluginManagementService.PluginLoaded += OnPluginManagementServiceOnPluginManagementLoaded; + _pluginManagementService.PluginEnabling += PluginManagementServiceOnPluginManagementEnabling; + _pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementEnabled; base.OnInitialActivate(); } protected override void OnClose() { _coreService.Initialized -= OnCoreServiceOnInitialized; - _pluginService.CopyingBuildInPlugins -= OnPluginServiceOnCopyingBuildInPlugins; - _pluginService.PluginLoading -= OnPluginServiceOnPluginLoading; - _pluginService.PluginLoaded -= OnPluginServiceOnPluginLoaded; - _pluginService.PluginEnabling -= PluginServiceOnPluginEnabling; - _pluginService.PluginEnabled -= PluginServiceOnPluginEnabled; + _pluginManagementService.CopyingBuildInPlugins -= OnPluginManagementServiceOnCopyingBuildInPluginsManagement; + _pluginManagementService.PluginLoading -= OnPluginManagementServiceOnPluginManagementLoading; + _pluginManagementService.PluginLoaded -= OnPluginManagementServiceOnPluginManagementLoaded; + _pluginManagementService.PluginEnabling -= PluginManagementServiceOnPluginManagementEnabling; + _pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginManagementEnabled; base.OnClose(); } - private void OnPluginServiceOnPluginLoaded(object sender, PluginEventArgs args) + private void OnPluginManagementServiceOnPluginManagementLoaded(object sender, PluginEventArgs args) { Status = "Initializing UI"; } - private void OnPluginServiceOnPluginLoading(object sender, PluginEventArgs args) + private void OnPluginManagementServiceOnPluginManagementLoading(object sender, PluginEventArgs args) { Status = "Loading plugin: " + args.PluginInfo.Name; } - private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs args) + private void PluginManagementServiceOnPluginManagementEnabled(object sender, PluginEventArgs args) { Status = "Initializing UI"; } - private void PluginServiceOnPluginEnabling(object sender, PluginEventArgs args) + private void PluginManagementServiceOnPluginManagementEnabling(object sender, PluginEventArgs args) { 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"; } diff --git a/src/Artemis.UI/Services/RegistrationService.cs b/src/Artemis.UI/Services/RegistrationService.cs index 1413abbca..c60671476 100644 --- a/src/Artemis.UI/Services/RegistrationService.cs +++ b/src/Artemis.UI/Services/RegistrationService.cs @@ -13,19 +13,19 @@ namespace Artemis.UI.Services { private readonly IDataModelUIService _dataModelUIService; private readonly IProfileEditorService _profileEditorService; - private readonly IPluginService _pluginService; + private readonly IPluginManagementService _pluginManagementService; private bool _registeredBuiltInDataModelDisplays; private bool _registeredBuiltInDataModelInputs; private bool _registeredBuiltInPropertyEditors; - public RegistrationService(IDataModelUIService dataModelUIService, IProfileEditorService profileEditorService, IPluginService pluginService) + public RegistrationService(IDataModelUIService dataModelUIService, IProfileEditorService profileEditorService, IPluginManagementService pluginManagementService) { _dataModelUIService = dataModelUIService; _profileEditorService = profileEditorService; - _pluginService = pluginService; + _pluginManagementService = pluginManagementService; LoadPluginModules(); - pluginService.PluginLoaded += PluginServiceOnPluginLoaded; + pluginManagementService.PluginLoaded += PluginServiceOnPluginLoaded; } public void RegisterBuiltInDataModelDisplays() @@ -80,7 +80,7 @@ namespace Artemis.UI.Services private void LoadPluginModules() { - foreach (PluginInfo pluginInfo in _pluginService.GetAllPluginInfo()) + foreach (PluginInfo pluginInfo in _pluginManagementService.GetAllPluginInfo()) pluginInfo.Kernel.Load(new[] { new PluginUIModule(pluginInfo) }); } }