1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Plugins - Separated plugins and implementations as different principles

This commit is contained in:
SpoinkyNL 2020-11-09 20:31:54 +01:00
parent c0d0e421c7
commit 1e0dc1894d
53 changed files with 438 additions and 410 deletions

View File

@ -34,10 +34,10 @@ namespace Artemis.Core
/// </summary>
public static readonly PluginInfo CorePluginInfo = new PluginInfo
{
Guid = Guid.Parse("ffffffff-ffff-ffff-ffff-ffffffffffff"), Name = "Artemis Core", Enabled = true
Guid = Guid.Parse("ffffffff-ffff-ffff-ffff-ffffffffffff"), Name = "Artemis Core", IsEnabled = true
};
internal static readonly CorePlugin CorePlugin = new CorePlugin {PluginInfo = CorePluginInfo};
internal static readonly CorePluginImplementation CorePluginImplementation = new CorePluginImplementation {PluginInfo = CorePluginInfo};
internal static readonly EffectPlaceholderPlugin EffectPlaceholderPlugin = new EffectPlaceholderPlugin {PluginInfo = CorePluginInfo};
/// <summary>

View File

@ -16,7 +16,7 @@ namespace Artemis.Core
{
internal EventPredicateWrapperDataModel()
{
PluginInfo = Constants.CorePluginInfo;
Implementation = Constants.CorePluginInfo;
}
[DataModelIgnore]

View File

@ -16,7 +16,7 @@ namespace Artemis.Core
{
internal ListPredicateWrapperDataModel()
{
PluginInfo = Constants.CorePluginInfo;
Implementation = Constants.CorePluginInfo;
}
[DataModelIgnore]

View File

@ -93,7 +93,7 @@ namespace Artemis.Core
/// <summary>
/// Gets the data model GUID of the <see cref="Target" /> if it is a <see cref="DataModel" />
/// </summary>
public Guid? DataModelGuid => Target?.PluginInfo.Guid;
public Guid? DataModelGuid => Target?.Implementation.Guid;
/// <summary>
/// Gets the point-separated path associated with this <see cref="DataModelPath" />
@ -295,7 +295,7 @@ namespace Artemis.Core
private void DataModelStoreOnDataModelAdded(object? sender, DataModelStoreEvent e)
{
if (e.Registration.DataModel.PluginInfo.Guid != Entity.DataModelGuid)
if (e.Registration.DataModel.Implementation.Guid != Entity.DataModelGuid)
return;
Target = e.Registration.DataModel;
@ -304,7 +304,7 @@ namespace Artemis.Core
private void DataModelStoreOnDataModelRemoved(object? sender, DataModelStoreEvent e)
{
if (e.Registration.DataModel.PluginInfo.Guid != Entity.DataModelGuid)
if (e.Registration.DataModel.Implementation.Guid != Entity.DataModelGuid)
return;
Target = null;

View File

@ -662,7 +662,7 @@ namespace Artemis.Core
return;
LayerBrushReference current = General.BrushReference.CurrentValue;
if (e.Registration.Plugin.PluginInfo.Guid == current.BrushPluginGuid &&
if (e.Registration.PluginImplementation.PluginInfo.Guid == current.BrushPluginGuid &&
e.Registration.LayerBrushDescriptor.LayerBrushType.Name == current.BrushType)
ActivateLayerBrush();
}

View File

@ -254,7 +254,7 @@ namespace Artemis.Core
{
// If effects provided by the plugin are on the element, replace them with placeholders
List<BaseLayerEffect> pluginEffects = _layerEffects.Where(ef => ef.Descriptor.LayerEffectProvider != null &&
ef.PluginInfo.Guid == e.Registration.Plugin.PluginInfo.Guid).ToList();
ef.PluginInfo.Guid == e.Registration.PluginImplementation.PluginInfo.Guid).ToList();
foreach (BaseLayerEffect pluginEffect in pluginEffects)
{
LayerEffectEntity entity = RenderElementEntity.LayerEffects.First(en => en.Id == pluginEffect.EntityId);
@ -268,7 +268,7 @@ namespace Artemis.Core
private void LayerEffectStoreOnLayerEffectAdded(object sender, LayerEffectStoreEvent e)
{
if (RenderElementEntity.LayerEffects.Any(ef => ef.PluginGuid == e.Registration.Plugin.PluginInfo.Guid))
if (RenderElementEntity.LayerEffects.Any(ef => ef.PluginGuid == e.Registration.PluginImplementation.PluginInfo.Guid))
ActivateEffects();
}

View File

@ -14,10 +14,10 @@ namespace Artemis.Core
private SKPath _renderPath;
private SKRect _renderRectangle;
internal ArtemisDevice(IRGBDevice rgbDevice, Plugin plugin, ArtemisSurface surface)
internal ArtemisDevice(IRGBDevice rgbDevice, PluginImplementation pluginImplementation, ArtemisSurface surface)
{
RgbDevice = rgbDevice;
Plugin = plugin;
PluginImplementation = pluginImplementation;
Surface = surface;
DeviceEntity = new DeviceEntity();
Leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
@ -30,10 +30,10 @@ namespace Artemis.Core
CalculateRenderProperties();
}
internal ArtemisDevice(IRGBDevice rgbDevice, Plugin plugin, ArtemisSurface surface, DeviceEntity deviceEntity)
internal ArtemisDevice(IRGBDevice rgbDevice, PluginImplementation pluginImplementation, ArtemisSurface surface, DeviceEntity deviceEntity)
{
RgbDevice = rgbDevice;
Plugin = plugin;
PluginImplementation = pluginImplementation;
Surface = surface;
DeviceEntity = deviceEntity;
Leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
@ -52,7 +52,7 @@ namespace Artemis.Core
}
public IRGBDevice RgbDevice { get; }
public Plugin Plugin { get; }
public PluginImplementation PluginImplementation { get; }
public ArtemisSurface Surface { get; }
public DeviceEntity DeviceEntity { get; }

View File

@ -17,7 +17,7 @@ namespace Artemis.Core.Ninject
protected override ISettingsService CreateInstance(IContext context)
{
IRequest parentRequest = context.Request.ParentRequest;
if (parentRequest == null || typeof(Plugin).IsAssignableFrom(parentRequest.Service))
if (parentRequest == null || typeof(PluginImplementation).IsAssignableFrom(parentRequest.Service))
throw new ArtemisPluginException($"SettingsService can not be injected into a plugin. Inject {nameof(PluginSettings)} instead.");
return _instance;

View File

@ -14,10 +14,10 @@ namespace Artemis.Core.DataModelExpansions
private readonly Dictionary<string, DataModel> _dynamicDataModels = new Dictionary<string, DataModel>();
/// <summary>
/// Gets the plugin info this data model belongs to
/// Gets the plugin implementation this data model belongs to
/// </summary>
[DataModelIgnore]
public PluginInfo PluginInfo { get; internal set; }
public DataModelPluginImplementation Implementation { get; internal set; }
/// <summary>
/// Gets the <see cref="DataModelPropertyAttribute" /> describing this data model
@ -43,9 +43,9 @@ namespace Artemis.Core.DataModelExpansions
/// <returns></returns>
public ReadOnlyCollection<PropertyInfo> GetHiddenProperties()
{
if (PluginInfo.Instance is ProfileModule profileModule)
if (Implementation is ProfileModule profileModule)
return profileModule.HiddenProperties;
if (PluginInfo.Instance is BaseDataModelExpansion dataModelExpansion)
if (Implementation is BaseDataModelExpansion dataModelExpansion)
return dataModelExpansion.HiddenProperties;
return new List<PropertyInfo>().AsReadOnly();
@ -81,7 +81,7 @@ namespace Artemis.Core.DataModelExpansions
throw new ArtemisCoreException($"Cannot add a dynamic data model with key '{key}' " +
"because the key is already in use by a static property on this data model.");
dynamicDataModel.PluginInfo = PluginInfo;
dynamicDataModel.Implementation = Implementation;
dynamicDataModel.DataModelDescription = new DataModelPropertyAttribute
{
Name = string.IsNullOrWhiteSpace(name) ? key.Humanize() : name,

View File

@ -42,18 +42,18 @@ namespace Artemis.Core.DataModelExpansions
HiddenPropertiesList.RemoveAll(p => p.Equals(propertyInfo));
}
internal override void InternalEnablePlugin()
internal override void InternalEnable()
{
DataModel = Activator.CreateInstance<T>();
DataModel.PluginInfo = PluginInfo;
DataModel.Implementation = PluginInfo;
DataModel.DataModelDescription = GetDataModelDescription();
base.InternalEnablePlugin();
base.InternalEnable();
}
internal override void InternalDisablePlugin()
internal override void InternalDisable()
{
DataModel = null;
base.InternalDisablePlugin();
base.InternalDisable();
}
}
}

View File

@ -8,7 +8,7 @@ namespace Artemis.Core.DataModelExpansions
/// For internal use only, to implement your own layer property type, extend <see cref="DataModelExpansion{T}" />
/// instead.
/// </summary>
public abstract class BaseDataModelExpansion : Plugin
public abstract class BaseDataModelExpansion : DataModelPluginImplementation
{
/// <summary>
/// Gets a list of all properties ignored at runtime using <c>IgnoreProperty(x => x.y)</c>

View File

@ -0,0 +1,47 @@
using System;
using System.Threading.Tasks;
namespace Artemis.Core
{
/// <summary>
/// Represents an implementation of a certain type provided by a plugin with support for data models
/// </summary>
public abstract class DataModelPluginImplementation : PluginImplementation
{
/// <summary>
/// Registers a timed update that whenever the plugin is enabled calls the provided <paramref name="action" /> at the
/// provided
/// <paramref name="interval" />
/// </summary>
/// <param name="interval">The interval at which the update should occur</param>
/// <param name="action">
/// The action to call every time the interval has passed. The delta time parameter represents the
/// time passed since the last update in seconds
/// </param>
/// <returns>The resulting plugin update registration which can be used to stop the update</returns>
public TimedUpdateRegistration AddTimedUpdate(TimeSpan interval, Action<double> action)
{
if (action == null)
throw new ArgumentNullException(nameof(action));
return new TimedUpdateRegistration(PluginInfo, interval, action);
}
/// <summary>
/// Registers a timed update that whenever the plugin is enabled calls the provided <paramref name="action" /> at the
/// provided
/// <paramref name="interval" />
/// </summary>
/// <param name="interval">The interval at which the update should occur</param>
/// <param name="asyncAction">
/// The async action to call every time the interval has passed. The delta time parameter
/// represents the time passed since the last update in seconds
/// </param>
/// <returns>The resulting plugin update registration</returns>
public TimedUpdateRegistration AddTimedUpdate(TimeSpan interval, Func<double, Task> asyncAction)
{
if (asyncAction == null)
throw new ArgumentNullException(nameof(asyncAction));
return new TimedUpdateRegistration(PluginInfo, interval, asyncAction);
}
}
}

View File

@ -10,7 +10,7 @@ namespace Artemis.Core.DeviceProviders
/// <summary>
/// Allows you to implement and register your own device provider
/// </summary>
public abstract class DeviceProvider : Plugin
public abstract class DeviceProvider : PluginImplementation
{
/// <summary>
/// Creates a new instance of the <see cref="DeviceProvider" /> class
@ -34,7 +34,7 @@ namespace Artemis.Core.DeviceProviders
public ILogger Logger { get; set; }
/// <inheritdoc />
public override void DisablePlugin()
public override void Disable()
{
// Does not happen with device providers, they require Artemis to restart
}

View File

@ -7,7 +7,7 @@ namespace Artemis.Core.LayerBrushes
/// <summary>
/// Allows you to create one or more <see cref="LayerBrush{T}" />s usable by profile layers.
/// </summary>
public abstract class LayerBrushProvider : Plugin
public abstract class LayerBrushProvider : PluginImplementation
{
private readonly List<LayerBrushDescriptor> _layerBrushDescriptors;
@ -17,7 +17,7 @@ namespace Artemis.Core.LayerBrushes
protected LayerBrushProvider()
{
_layerBrushDescriptors = new List<LayerBrushDescriptor>();
PluginDisabled += OnPluginDisabled;
Disabled += OnDisabled;
}
/// <summary>
@ -38,7 +38,7 @@ namespace Artemis.Core.LayerBrushes
/// </param>
protected void RegisterLayerBrushDescriptor<T>(string displayName, string description, string icon) where T : BaseLayerBrush
{
if (!Enabled)
if (!IsEnabled)
throw new ArtemisPluginException(PluginInfo, "Can only add a layer brush descriptor when the plugin is enabled");
LayerBrushDescriptor descriptor = new LayerBrushDescriptor(displayName, description, icon, typeof(T), this);
@ -46,7 +46,7 @@ namespace Artemis.Core.LayerBrushes
LayerBrushStore.Add(descriptor);
}
private void OnPluginDisabled(object sender, EventArgs e)
private void OnDisabled(object sender, EventArgs e)
{
// The store will clean up the registrations by itself, the plugin just needs to clear its own list
_layerBrushDescriptors.Clear();

View File

@ -7,7 +7,7 @@ namespace Artemis.Core.LayerEffects
/// <summary>
/// Allows you to register one or more <see cref="LayerEffect{T}" />s usable by profile layers.
/// </summary>
public abstract class LayerEffectProvider : Plugin
public abstract class LayerEffectProvider : PluginImplementation
{
private readonly List<LayerEffectDescriptor> _layerEffectDescriptors;
@ -17,7 +17,7 @@ namespace Artemis.Core.LayerEffects
protected LayerEffectProvider()
{
_layerEffectDescriptors = new List<LayerEffectDescriptor>();
PluginDisabled += OnPluginDisabled;
Disabled += OnDisabled;
}
/// <summary>
@ -38,7 +38,7 @@ namespace Artemis.Core.LayerEffects
/// </param>
protected void RegisterLayerEffectDescriptor<T>(string displayName, string description, string icon) where T : BaseLayerEffect
{
if (!Enabled)
if (!IsEnabled)
throw new ArtemisPluginException(PluginInfo, "Can only add a layer effect descriptor when the plugin is enabled");
LayerEffectDescriptor descriptor = new LayerEffectDescriptor(displayName, description, icon, typeof(T), this);
@ -46,7 +46,7 @@ namespace Artemis.Core.LayerEffects
LayerEffectStore.Add(descriptor);
}
private void OnPluginDisabled(object sender, EventArgs e)
private void OnDisabled(object sender, EventArgs e)
{
// The store will clean up the registrations by itself, the plugin just needs to clear its own list
_layerEffectDescriptors.Clear();

View File

@ -45,18 +45,18 @@ namespace Artemis.Core.Modules
return new DataModelPropertyAttribute {Name = PluginInfo.Name, Description = PluginInfo.Description};
}
internal override void InternalEnablePlugin()
internal override void InternalEnable()
{
DataModel = Activator.CreateInstance<T>();
DataModel.PluginInfo = PluginInfo;
DataModel.Implementation = PluginInfo;
DataModel.DataModelDescription = GetDataModelDescription();
base.InternalEnablePlugin();
base.InternalEnable();
}
internal override void InternalDisablePlugin()
internal override void InternalDisable()
{
DataModel = null;
base.InternalDisablePlugin();
base.InternalDisable();
}
}
@ -64,7 +64,7 @@ namespace Artemis.Core.Modules
/// <summary>
/// Allows you to add support for new games/applications
/// </summary>
public abstract class Module : Plugin
public abstract class Module : DataModelPluginImplementation
{
/// <summary>
/// The modules display name that's shown in the menu

View File

@ -71,18 +71,18 @@ namespace Artemis.Core.Modules
HiddenPropertiesList.RemoveAll(p => p.Equals(propertyInfo));
}
internal override void InternalEnablePlugin()
internal override void InternalEnable()
{
DataModel = Activator.CreateInstance<T>();
DataModel.PluginInfo = PluginInfo;
DataModel.Implementation = PluginInfo;
DataModel.DataModelDescription = GetDataModelDescription();
base.InternalEnablePlugin();
base.InternalEnable();
}
internal override void InternalDisablePlugin()
internal override void InternalDisable()
{
Deactivate(true);
base.InternalDisablePlugin();
base.InternalDisable();
DataModel = null;
}
}

View File

@ -1,178 +1,18 @@
using System;
using System.Threading.Tasks;
namespace Artemis.Core
namespace Artemis.Core
{
/// <summary>
/// This is the base plugin type, use the other interfaces such as Module to create plugins
/// Represents a plugin
/// </summary>
public abstract class Plugin : IDisposable
public abstract class Plugin
{
/// <summary>
/// Gets the plugin info related to this plugin
/// </summary>
public PluginInfo PluginInfo { get; internal set; }
/// <summary>
/// Gets whether the plugin is enabled
/// </summary>
public bool Enabled { get; internal set; }
public PluginInfo Info { get; internal set; }
/// <summary>
/// Gets or sets a configuration dialog for this plugin that is accessible in the UI under Settings > Plugins
/// </summary>
public PluginConfigurationDialog ConfigurationDialog { get; protected set; }
/// <summary>
/// Called when the plugin is activated
/// </summary>
public abstract void EnablePlugin();
/// <summary>
/// Called when the plugin is deactivated or when Artemis shuts down
/// </summary>
public abstract void DisablePlugin();
/// <summary>
/// Registers a timed update that whenever the plugin is enabled calls the provided <paramref name="action" /> at the
/// provided
/// <paramref name="interval" />
/// </summary>
/// <param name="interval">The interval at which the update should occur</param>
/// <param name="action">
/// The action to call every time the interval has passed. The delta time parameter represents the
/// time passed since the last update in seconds
/// </param>
/// <returns>The resulting plugin update registration which can be used to stop the update</returns>
public PluginUpdateRegistration AddTimedUpdate(TimeSpan interval, Action<double> action)
{
if (action == null)
throw new ArgumentNullException(nameof(action));
return new PluginUpdateRegistration(PluginInfo, interval, action);
}
/// <summary>
/// Registers a timed update that whenever the plugin is enabled calls the provided <paramref name="action" /> at the
/// provided
/// <paramref name="interval" />
/// </summary>
/// <param name="interval">The interval at which the update should occur</param>
/// <param name="asyncAction">
/// The async action to call every time the interval has passed. The delta time parameter
/// represents the time passed since the last update in seconds
/// </param>
/// <returns>The resulting plugin update registration</returns>
public PluginUpdateRegistration AddTimedUpdate(TimeSpan interval, Func<double, Task> asyncAction)
{
if (asyncAction == null)
throw new ArgumentNullException(nameof(asyncAction));
return new PluginUpdateRegistration(PluginInfo, interval, asyncAction);
}
internal void SetEnabled(bool enable, bool isAutoEnable = false)
{
if (enable && !Enabled)
{
try
{
if (isAutoEnable && PluginInfo.GetLockFileCreated())
{
// Don't wrap existing lock exceptions, simply rethrow them
if (PluginInfo.LoadException is ArtemisPluginLockException)
throw PluginInfo.LoadException;
throw new ArtemisPluginLockException(PluginInfo.LoadException);
}
Enabled = true;
PluginInfo.Enabled = true;
PluginInfo.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(InternalEnablePlugin);
if (!enableTask.Wait(TimeSpan.FromSeconds(15)))
throw new ArtemisPluginException(PluginInfo, "Plugin load timeout");
PluginInfo.LoadException = null;
OnPluginEnabled();
}
// If enable failed, put it back in a disabled state
catch (Exception e)
{
Enabled = false;
PluginInfo.Enabled = false;
PluginInfo.LoadException = e;
throw;
}
finally
{
if (!(PluginInfo.LoadException is ArtemisPluginLockException))
PluginInfo.DeleteLockFile();
}
}
else if (!enable && Enabled)
{
Enabled = false;
PluginInfo.Enabled = false;
// Even if disable failed, still leave it in a disabled state to avoid more issues
InternalDisablePlugin();
OnPluginDisabled();
}
// 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 && !Enabled)
{
PluginInfo.Enabled = false;
}
}
internal virtual void InternalEnablePlugin()
{
EnablePlugin();
}
internal virtual void InternalDisablePlugin()
{
DisablePlugin();
}
/// <inheritdoc />
public void Dispose()
{
DisablePlugin();
}
#region Events
/// <summary>
/// Occurs when the plugin is enabled
/// </summary>
public event EventHandler PluginEnabled;
/// <summary>
/// Occurs when the plugin is disabled
/// </summary>
public event EventHandler PluginDisabled;
/// <summary>
/// Triggers the PluginEnabled event
/// </summary>
protected virtual void OnPluginEnabled()
{
PluginEnabled?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Triggers the PluginDisabled event
/// </summary>
protected virtual void OnPluginDisabled()
{
PluginDisabled?.Invoke(this, EventArgs.Empty);
}
#endregion
}
}

View File

@ -17,7 +17,7 @@ namespace Artemis.Core
/// <summary>
/// The layer brush this dialog belongs to
/// </summary>
internal Plugin Plugin { get; set; }
internal PluginImplementation PluginImplementation { get; set; }
/// <summary>
/// The type of view model the tab contains

View File

@ -10,25 +10,25 @@ namespace Artemis.Core
/// <summary>
/// Creates a new instance of the <see cref="PluginConfigurationViewModel" /> class
/// </summary>
/// <param name="plugin"></param>
protected PluginConfigurationViewModel(Plugin plugin)
/// <param name="pluginImplementation"></param>
protected PluginConfigurationViewModel(PluginImplementation pluginImplementation)
{
Plugin = plugin;
PluginImplementation = pluginImplementation;
}
/// <summary>
/// Creates a new instance of the <see cref="PluginConfigurationViewModel" /> class with a validator
/// </summary>
/// <param name="plugin"></param>
/// <param name="pluginImplementation"></param>
/// <param name="validator"></param>
protected PluginConfigurationViewModel(Plugin plugin, IModelValidator validator) : base(validator)
protected PluginConfigurationViewModel(PluginImplementation pluginImplementation, IModelValidator validator) : base(validator)
{
Plugin = plugin;
PluginImplementation = pluginImplementation;
}
/// <summary>
/// Gets the plugin this configuration view model is associated with
/// </summary>
public Plugin Plugin { get; }
public PluginImplementation PluginImplementation { get; }
}
}

View File

@ -0,0 +1,142 @@
using System;
using System.Threading.Tasks;
namespace Artemis.Core
{
/// <summary>
/// Represents an implementation of a certain type provided by a plugin
/// </summary>
public abstract class PluginImplementation : IDisposable
{
/// <summary>
/// Gets the plugin that provides this implementation
/// </summary>
public Plugin Plugin { get; internal set; }
/// <summary>
/// Gets the plugin info related to this plugin
/// </summary>
public PluginInfo PluginInfo { get; internal set; }
/// <summary>
/// Gets whether the plugin is enabled
/// </summary>
public bool IsEnabled { get; internal set; }
/// <summary>
/// Called when the implementation is activated
/// </summary>
public abstract void Enable();
/// <summary>
/// Called when the implementation is deactivated or when Artemis shuts down
/// </summary>
public abstract void Disable();
internal void SetEnabled(bool enable, bool isAutoEnable = false)
{
if (enable && !IsEnabled)
{
try
{
if (isAutoEnable && PluginInfo.GetLockFileCreated())
{
// Don't wrap existing lock exceptions, simply rethrow them
if (PluginInfo.LoadException is ArtemisPluginLockException)
throw PluginInfo.LoadException;
throw new ArtemisPluginLockException(PluginInfo.LoadException);
}
IsEnabled = true;
PluginInfo.IsEnabled = true;
PluginInfo.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");
PluginInfo.LoadException = null;
OnEnabled();
}
// If enable failed, put it back in a disabled state
catch (Exception e)
{
IsEnabled = false;
PluginInfo.IsEnabled = false;
PluginInfo.LoadException = e;
throw;
}
finally
{
if (!(PluginInfo.LoadException is ArtemisPluginLockException))
PluginInfo.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()
{
Enable();
}
internal virtual void InternalDisable()
{
Disable();
}
/// <inheritdoc />
public void Dispose()
{
Disable();
}
#region Events
/// <summary>
/// Occurs when the implementation is enabled
/// </summary>
public event EventHandler? Enabled;
/// <summary>
/// Occurs when the implementation is disabled
/// </summary>
public event EventHandler? Disabled;
/// <summary>
/// Triggers the PluginEnabled event
/// </summary>
protected virtual void OnEnabled()
{
Enabled?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// Triggers the PluginDisabled event
/// </summary>
protected virtual void OnDisabled()
{
Disabled?.Invoke(this, EventArgs.Empty);
}
#endregion
}
}

View File

@ -5,7 +5,6 @@ using Artemis.Storage.Entities.Plugins;
using McMaster.NETCore.Plugins;
using Newtonsoft.Json;
using Ninject;
using Ninject.Extensions.ChildKernel;
using Stylet;
namespace Artemis.Core
@ -18,10 +17,10 @@ namespace Artemis.Core
{
private string _description;
private DirectoryInfo _directory;
private bool _enabled;
private Guid _guid;
private string _icon;
private Plugin _instance;
private bool _isEnabled;
private Exception _loadException;
private string _main;
private string _name;
@ -103,7 +102,7 @@ namespace Artemis.Core
}
/// <summary>
/// A reference to the type implementing Plugin, available after successful load
/// Gets the plugin this info is associated with
/// </summary>
public Plugin Instance
{
@ -114,10 +113,10 @@ namespace Artemis.Core
/// <summary>
/// Indicates whether the user enabled the plugin or not
/// </summary>
public bool Enabled
public bool IsEnabled
{
get => _enabled;
internal set => SetAndNotify(ref _enabled, value);
get => _isEnabled;
internal set => SetAndNotify(ref _isEnabled, value);
}
/// <summary>
@ -129,36 +128,41 @@ namespace Artemis.Core
internal set => SetAndNotify(ref _loadException, value);
}
/// <summary>
/// The PluginLoader backing this plugin
/// </summary>
internal PluginLoader PluginLoader { get; set; }
/// <summary>
/// The assembly the plugin code lives in
/// </summary>
public Assembly Assembly { get; internal set; }
/// <summary>
/// The Ninject kernel of the plugin
/// 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 />
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 = Enabled;
PluginEntity.IsEnabled = IsEnabled;
}
internal void CreateLockFile()
@ -176,10 +180,5 @@ namespace Artemis.Core
{
return File.Exists(Path.Combine(Directory.FullName, "artemis.lock"));
}
public string? ResolveRelativePath(string path)
{
return path == null ? null : Path.Combine(Directory.FullName, path);
}
}
}

View File

@ -8,32 +8,32 @@ namespace Artemis.Core
/// <summary>
/// Represents a registration for a timed plugin update
/// </summary>
public class PluginUpdateRegistration
public class TimedUpdateRegistration
{
private DateTime _lastEvent;
private Timer _timer;
internal PluginUpdateRegistration(PluginInfo pluginInfo, TimeSpan interval, Action<double> action)
internal TimedUpdateRegistration(PluginInfo pluginInfo, TimeSpan interval, Action<double> action)
{
PluginInfo = pluginInfo;
Interval = interval;
Action = action;
PluginInfo.Instance.PluginEnabled += InstanceOnPluginEnabled;
PluginInfo.Instance.PluginDisabled += InstanceOnPluginDisabled;
if (PluginInfo.Instance.Enabled)
PluginInfo.Instance.Enabled += InstanceOnEnabled;
PluginInfo.Instance.Disabled += InstanceOnDisabled;
if (PluginInfo.Instance.IsEnabled)
Start();
}
internal PluginUpdateRegistration(PluginInfo pluginInfo, TimeSpan interval, Func<double, Task> asyncAction)
internal TimedUpdateRegistration(PluginInfo pluginInfo, TimeSpan interval, Func<double, Task> asyncAction)
{
PluginInfo = pluginInfo;
Interval = interval;
AsyncAction = asyncAction;
PluginInfo.Instance.PluginEnabled += InstanceOnPluginEnabled;
PluginInfo.Instance.PluginDisabled += InstanceOnPluginDisabled;
if (PluginInfo.Instance.Enabled)
PluginInfo.Instance.Enabled += InstanceOnEnabled;
PluginInfo.Instance.Disabled += InstanceOnDisabled;
if (PluginInfo.Instance.IsEnabled)
Start();
}
@ -66,7 +66,7 @@ namespace Artemis.Core
{
lock (this)
{
if (!PluginInfo.Instance.Enabled)
if (!PluginInfo.Instance.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.Enabled)
if (!PluginInfo.Instance.IsEnabled)
return;
lock (this)
@ -121,12 +121,12 @@ namespace Artemis.Core
}
}
private void InstanceOnPluginEnabled(object sender, EventArgs e)
private void InstanceOnEnabled(object sender, EventArgs e)
{
Start();
}
private void InstanceOnPluginDisabled(object sender, EventArgs e)
private void InstanceOnDisabled(object sender, EventArgs e)
{
Stop();
}

View File

@ -133,8 +133,8 @@ namespace Artemis.Core.Services
private void UpdatePluginCache()
{
_modules = _pluginService.GetPluginsOfType<Module>().Where(p => p.Enabled).ToList();
_dataModelExpansions = _pluginService.GetPluginsOfType<BaseDataModelExpansion>().Where(p => p.Enabled).ToList();
_modules = _pluginService.GetPluginsOfType<Module>().Where(p => p.IsEnabled).ToList();
_dataModelExpansions = _pluginService.GetPluginsOfType<BaseDataModelExpansion>().Where(p => p.IsEnabled).ToList();
}
private void ConfigureJsonConvert()
@ -162,7 +162,7 @@ namespace Artemis.Core.Services
lock (_dataModelExpansions)
{
// Update all active modules, check Enabled status because it may go false before before the _dataModelExpansions list is updated
foreach (BaseDataModelExpansion dataModelExpansion in _dataModelExpansions.Where(e => e.Enabled))
foreach (BaseDataModelExpansion dataModelExpansion in _dataModelExpansions.Where(e => e.IsEnabled))
dataModelExpansion.Update(args.DeltaTime);
}

View File

@ -46,22 +46,22 @@ namespace Artemis.Core.Services
/// <summary>
/// Enables the provided plugin
/// </summary>
/// <param name="plugin"></param>
/// <param name="pluginImplementation"></param>
/// <param name="isAutoEnable">If true, fails if there is a lock file present</param>
void EnablePlugin(Plugin plugin, bool isAutoEnable = false);
void EnablePlugin(PluginImplementation pluginImplementation, bool isAutoEnable = false);
/// <summary>
/// Disables the provided plugin
/// </summary>
/// <param name="plugin"></param>
void DisablePlugin(Plugin plugin);
/// <param name="pluginImplementation"></param>
void DisablePlugin(PluginImplementation pluginImplementation);
/// <summary>
/// Finds the plugin info related to the plugin
/// </summary>
/// <param name="plugin">The plugin you want to find the plugin info for</param>
/// <param name="pluginImplementation">The plugin you want to find the plugin info for</param>
/// <returns>The plugins PluginInfo</returns>
PluginInfo GetPluginInfo(Plugin plugin);
PluginInfo GetPluginInfo(PluginImplementation pluginImplementation);
/// <summary>
/// Gets the plugin info of all loaded plugins
@ -70,31 +70,31 @@ namespace Artemis.Core.Services
List<PluginInfo> GetAllPluginInfo();
/// <summary>
/// Finds all enabled <see cref="Plugin" /> instances of <typeparamref name="T" />
/// Finds all enabled <see cref="PluginImplementation" /> instances of <typeparamref name="T" />
/// </summary>
/// <typeparam name="T">Either <see cref="Plugin" /> or a plugin type implementing <see cref="Plugin" /></typeparam>
/// <typeparam name="T">Either <see cref="PluginImplementation" /> or a plugin type implementing <see cref="PluginImplementation" /></typeparam>
/// <returns>Returns a list of plugin instances of <typeparamref name="T" /></returns>
List<T> GetPluginsOfType<T>() where T : Plugin;
List<T> GetPluginsOfType<T>() where T : PluginImplementation;
/// <summary>
/// Gets the plugin that provided the specified assembly
/// </summary>
/// <param name="assembly"></param>
/// <returns></returns>
Plugin GetPluginByAssembly(Assembly assembly);
PluginImplementation GetPluginByAssembly(Assembly assembly);
/// <summary>
/// Gets the plugin that defined the specified device
/// </summary>
/// <param name="device"></param>
/// <returns></returns>
Plugin GetPluginByDevice(IRGBDevice device);
PluginImplementation GetPluginByDevice(IRGBDevice device);
/// <summary>
/// Returns the plugin info of the current call stack
/// </summary>
/// <returns>If the current call stack contains a plugin, the plugin. Otherwise null</returns>
Plugin GetCallingPlugin();
PluginImplementation GetCallingPlugin();
#region Events

View File

@ -103,7 +103,7 @@ namespace Artemis.Core.Services
{
lock (module)
{
bool shouldBeActivated = module.EvaluateActivationRequirements() && module.Enabled;
bool shouldBeActivated = module.EvaluateActivationRequirements() && module.IsEnabled;
if (shouldBeActivated && !module.IsActivated)
tasks.Add(ActivateModule(module));
else if (!shouldBeActivated && module.IsActivated)

View File

@ -136,7 +136,7 @@ namespace Artemis.Core.Services
}
// Activate plugins after they are all loaded
foreach (PluginInfo pluginInfo in _plugins.Where(p => p.Enabled))
foreach (PluginInfo pluginInfo in _plugins.Where(p => p.IsEnabled))
{
try
{
@ -180,7 +180,7 @@ namespace Artemis.Core.Services
pluginEntity = new PluginEntity {Id = pluginInfo.Guid, IsEnabled = true};
pluginInfo.PluginEntity = pluginEntity;
pluginInfo.Enabled = pluginEntity.IsEnabled;
pluginInfo.IsEnabled = pluginEntity.IsEnabled;
string mainFile = Path.Combine(pluginInfo.Directory.FullName, pluginInfo.Main);
if (!File.Exists(mainFile))
@ -206,7 +206,7 @@ namespace Artemis.Core.Services
List<Type> pluginTypes;
try
{
pluginTypes = pluginInfo.Assembly.GetTypes().Where(t => typeof(Plugin).IsAssignableFrom(t)).ToList();
pluginTypes = pluginInfo.Assembly.GetTypes().Where(t => typeof(PluginImplementation).IsAssignableFrom(t)).ToList();
}
catch (ReflectionTypeLoadException e)
{
@ -226,7 +226,7 @@ namespace Artemis.Core.Services
};
pluginInfo.Kernel = new ChildKernel(_kernel);
pluginInfo.Kernel.Load(new PluginModule(pluginInfo));
pluginInfo.Instance = (Plugin) pluginInfo.Kernel.Get(pluginType, constraint: null, parameters: parameters);
pluginInfo.Instance = (PluginImplementation) pluginInfo.Kernel.Get(pluginType, constraint: null, parameters: parameters);
pluginInfo.Instance.PluginInfo = pluginInfo;
}
catch (Exception e)
@ -266,29 +266,29 @@ namespace Artemis.Core.Services
}
}
public void EnablePlugin(Plugin plugin, bool isAutoEnable = false)
public void EnablePlugin(PluginImplementation pluginImplementation, bool isAutoEnable = false)
{
_logger.Debug("Enabling plugin {pluginInfo}", plugin.PluginInfo);
OnPluginEnabling(new PluginEventArgs(plugin.PluginInfo));
_logger.Debug("Enabling plugin {pluginInfo}", pluginImplementation.PluginInfo);
OnPluginEnabling(new PluginEventArgs(pluginImplementation.PluginInfo));
lock (_plugins)
{
try
{
// A device provider may be queued for disable on next restart, this undoes that
if (plugin is DeviceProvider && plugin.Enabled && !plugin.PluginInfo.Enabled)
if (pluginImplementation is DeviceProvider && pluginImplementation.IsEnabled && !pluginImplementation.PluginInfo.IsEnabled)
{
plugin.PluginInfo.Enabled = true;
plugin.PluginInfo.ApplyToEntity();
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
pluginImplementation.PluginInfo.IsEnabled = true;
pluginImplementation.PluginInfo.ApplyToEntity();
_pluginRepository.SavePlugin(pluginImplementation.PluginInfo.PluginEntity);
return;
}
plugin.SetEnabled(true, isAutoEnable);
pluginImplementation.SetEnabled(true, isAutoEnable);
}
catch (Exception e)
{
_logger.Warning(new ArtemisPluginException(plugin.PluginInfo, "Exception during SetEnabled(true)", e), "Failed to enable plugin");
_logger.Warning(new ArtemisPluginException(pluginImplementation.PluginInfo, "Exception during SetEnabled(true)", e), "Failed to enable plugin");
throw;
}
finally
@ -296,48 +296,48 @@ namespace Artemis.Core.Services
// On an auto-enable, ensure PluginInfo.Enabled is true even if enable failed, that way a failure on auto-enable does
// not affect the user's settings
if (isAutoEnable)
plugin.PluginInfo.Enabled = true;
pluginImplementation.PluginInfo.IsEnabled = true;
plugin.PluginInfo.ApplyToEntity();
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
pluginImplementation.PluginInfo.ApplyToEntity();
_pluginRepository.SavePlugin(pluginImplementation.PluginInfo.PluginEntity);
if (plugin.PluginInfo.Enabled)
_logger.Debug("Successfully enabled plugin {pluginInfo}", plugin.PluginInfo);
if (pluginImplementation.PluginInfo.IsEnabled)
_logger.Debug("Successfully enabled plugin {pluginInfo}", pluginImplementation.PluginInfo);
}
}
OnPluginEnabled(new PluginEventArgs(plugin.PluginInfo));
OnPluginEnabled(new PluginEventArgs(pluginImplementation.PluginInfo));
}
public void DisablePlugin(Plugin plugin)
public void DisablePlugin(PluginImplementation pluginImplementation)
{
lock (_plugins)
{
_logger.Debug("Disabling plugin {pluginInfo}", plugin.PluginInfo);
_logger.Debug("Disabling plugin {pluginInfo}", pluginImplementation.PluginInfo);
// Device providers cannot be disabled at runtime simply queue a disable for next restart
if (plugin is DeviceProvider)
if (pluginImplementation is DeviceProvider)
{
// Don't call SetEnabled(false) but simply update enabled state and save it
plugin.PluginInfo.Enabled = false;
plugin.PluginInfo.ApplyToEntity();
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
pluginImplementation.PluginInfo.IsEnabled = false;
pluginImplementation.PluginInfo.ApplyToEntity();
_pluginRepository.SavePlugin(pluginImplementation.PluginInfo.PluginEntity);
return;
}
plugin.SetEnabled(false);
plugin.PluginInfo.ApplyToEntity();
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
pluginImplementation.SetEnabled(false);
pluginImplementation.PluginInfo.ApplyToEntity();
_pluginRepository.SavePlugin(pluginImplementation.PluginInfo.PluginEntity);
_logger.Debug("Successfully disabled plugin {pluginInfo}", plugin.PluginInfo);
_logger.Debug("Successfully disabled plugin {pluginInfo}", pluginImplementation.PluginInfo);
}
OnPluginDisabled(new PluginEventArgs(plugin.PluginInfo));
OnPluginDisabled(new PluginEventArgs(pluginImplementation.PluginInfo));
}
public PluginInfo GetPluginInfo(Plugin plugin)
public PluginInfo GetPluginInfo(PluginImplementation pluginImplementation)
{
return _plugins.FirstOrDefault(p => p.Instance == plugin);
return _plugins.FirstOrDefault(p => p.Instance == pluginImplementation);
}
public List<PluginInfo> GetAllPluginInfo()
@ -345,22 +345,22 @@ namespace Artemis.Core.Services
return new List<PluginInfo>(_plugins);
}
public List<T> GetPluginsOfType<T>() where T : Plugin
public List<T> GetPluginsOfType<T>() where T : PluginImplementation
{
return _plugins.Where(p => p.Enabled && p.Instance is T).Select(p => (T) p.Instance).ToList();
return _plugins.Where(p => p.IsEnabled && p.Instance is T).Select(p => (T) p.Instance).ToList();
}
public Plugin GetPluginByAssembly(Assembly assembly)
public PluginImplementation GetPluginByAssembly(Assembly assembly)
{
return _plugins.FirstOrDefault(p => p.Assembly == assembly)?.Instance;
}
public Plugin GetPluginByDevice(IRGBDevice rgbDevice)
public PluginImplementation GetPluginByDevice(IRGBDevice rgbDevice)
{
return GetPluginsOfType<DeviceProvider>().First(d => d.RgbDeviceProvider.Devices != null && d.RgbDeviceProvider.Devices.Contains(rgbDevice));
}
public Plugin GetCallingPlugin()
public PluginImplementation GetCallingPlugin()
{
StackTrace stackTrace = new StackTrace(); // get call stack
StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames)
@ -368,9 +368,9 @@ namespace Artemis.Core.Services
foreach (StackFrame stackFrame in stackFrames)
{
Assembly assembly = stackFrame.GetMethod().DeclaringType.Assembly;
Plugin plugin = GetPluginByAssembly(assembly);
if (plugin != null)
return plugin;
PluginImplementation pluginImplementation = GetPluginByAssembly(assembly);
if (pluginImplementation != null)
return pluginImplementation;
}
return null;

View File

@ -11,9 +11,9 @@ namespace Artemis.Core.Services
public DataModelService(IPluginService pluginService)
{
// Add data models of already loaded plugins
foreach (Module module in pluginService.GetPluginsOfType<Module>().Where(p => p.Enabled))
foreach (Module module in pluginService.GetPluginsOfType<Module>().Where(p => p.IsEnabled))
AddModuleDataModel(module);
foreach (BaseDataModelExpansion dataModelExpansion in pluginService.GetPluginsOfType<BaseDataModelExpansion>().Where(p => p.Enabled))
foreach (BaseDataModelExpansion dataModelExpansion in pluginService.GetPluginsOfType<BaseDataModelExpansion>().Where(p => p.IsEnabled))
AddDataModelExpansionDataModel(dataModelExpansion);
// Add data models of new plugins when they get enabled
@ -44,9 +44,9 @@ namespace Artemis.Core.Services
return (T) DataModelStore.GetAll().FirstOrDefault(d => d.DataModel is T)?.DataModel;
}
public DataModel GetPluginDataModel(Plugin plugin)
public DataModel GetPluginDataModel(PluginImplementation pluginImplementation)
{
return DataModelStore.Get(plugin.PluginInfo.Guid)?.DataModel;
return DataModelStore.Get(pluginImplementation.PluginInfo.Guid)?.DataModel;
}
public DataModel GetPluginDataModel(Guid pluginGuid)

View File

@ -34,8 +34,8 @@ namespace Artemis.Core.Services
/// <summary>
/// If found, returns the data model of the provided plugin
/// </summary>
/// <param name="plugin">The plugin to find the data model of</param>
DataModel GetPluginDataModel(Plugin plugin);
/// <param name="pluginImplementation">The plugin to find the data model of</param>
DataModel GetPluginDataModel(PluginImplementation pluginImplementation);
/// <summary>
/// If found, returns the data model of the provided plugin GUID

View File

@ -44,8 +44,8 @@ namespace Artemis.Core.Services
// Add all current devices
foreach (IRGBDevice rgbDevice in _rgbService.LoadedDevices)
{
Plugin plugin = _pluginService.GetPluginByDevice(rgbDevice);
configuration.Devices.Add(new ArtemisDevice(rgbDevice, plugin, configuration));
PluginImplementation pluginImplementation = _pluginService.GetPluginByDevice(rgbDevice);
configuration.Devices.Add(new ArtemisDevice(rgbDevice, pluginImplementation, configuration));
}
lock (_surfaceConfigurations)
@ -136,8 +136,8 @@ namespace Artemis.Core.Services
IRGBDevice device = _rgbService.Surface.Devices.FirstOrDefault(d => d.GetDeviceIdentifier() == position.DeviceIdentifier);
if (device != null)
{
Plugin plugin = _pluginService.GetPluginByDevice(device);
surfaceConfiguration.Devices.Add(new ArtemisDevice(device, plugin, surfaceConfiguration, position));
PluginImplementation pluginImplementation = _pluginService.GetPluginByDevice(device);
surfaceConfiguration.Devices.Add(new ArtemisDevice(device, pluginImplementation, surfaceConfiguration, position));
}
}
@ -178,8 +178,8 @@ namespace Artemis.Core.Services
DeviceEntity existingDeviceConfig = surface.SurfaceEntity.DeviceEntities.FirstOrDefault(d => d.DeviceIdentifier == deviceIdentifier);
if (existingDeviceConfig != null)
{
Plugin plugin = _pluginService.GetPluginByDevice(rgbDevice);
device = new ArtemisDevice(rgbDevice, plugin, surface, existingDeviceConfig);
PluginImplementation pluginImplementation = _pluginService.GetPluginByDevice(rgbDevice);
device = new ArtemisDevice(rgbDevice, pluginImplementation, surface, existingDeviceConfig);
}
// Fall back on creating a new device
else
@ -189,8 +189,8 @@ namespace Artemis.Core.Services
rgbDevice.DeviceInfo,
deviceIdentifier
);
Plugin plugin = _pluginService.GetPluginByDevice(rgbDevice);
device = new ArtemisDevice(rgbDevice, plugin, surface);
PluginImplementation pluginImplementation = _pluginService.GetPluginByDevice(rgbDevice);
device = new ArtemisDevice(rgbDevice, pluginImplementation, surface);
}
surface.Devices.Add(device);

View File

@ -42,7 +42,7 @@ namespace Artemis.Core
{
lock (Registrations)
{
return Registrations.FirstOrDefault(r => r.Plugin.PluginInfo.Guid == pluginGuid && r.ConditionOperator.GetType().Name == type);
return Registrations.FirstOrDefault(r => r.PluginImplementation.PluginInfo.Guid == pluginGuid && r.ConditionOperator.GetType().Name == type);
}
}

View File

@ -42,7 +42,7 @@ namespace Artemis.Core
{
lock (Registrations)
{
return Registrations.FirstOrDefault(r => r.Plugin.PluginInfo.Guid == pluginGuid && r.DataBindingModifierType.GetType().Name == type);
return Registrations.FirstOrDefault(r => r.PluginImplementation.PluginInfo.Guid == pluginGuid && r.DataBindingModifierType.GetType().Name == type);
}
}

View File

@ -17,7 +17,7 @@ namespace Artemis.Core
if (Registrations.Any(r => r.DataModel == dataModel))
throw new ArtemisCoreException($"Data model store already contains data model '{dataModel.DataModelDescription}'");
registration = new DataModelRegistration(dataModel, dataModel.PluginInfo.Instance) {IsInStore = true};
registration = new DataModelRegistration(dataModel, dataModel.Implementation.Instance) {IsInStore = true};
Registrations.Add(registration);
}
@ -51,7 +51,7 @@ namespace Artemis.Core
{
lock (Registrations)
{
return Registrations.FirstOrDefault(d => d.Plugin.PluginInfo.Guid == pluginGuid);
return Registrations.FirstOrDefault(d => d.PluginImplementation.PluginInfo.Guid == pluginGuid);
}
}

View File

@ -51,7 +51,7 @@ namespace Artemis.Core
{
lock (Registrations)
{
return Registrations.FirstOrDefault(d => d.Plugin.PluginInfo.Guid == pluginGuid &&
return Registrations.FirstOrDefault(d => d.PluginImplementation.PluginInfo.Guid == pluginGuid &&
d.LayerBrushDescriptor.LayerBrushType.Name == typeName);
}
}

View File

@ -51,7 +51,7 @@ namespace Artemis.Core
{
lock (Registrations)
{
return Registrations.FirstOrDefault(d => d.Plugin.PluginInfo.Guid == pluginGuid && d.LayerEffectDescriptor.LayerEffectType.Name == typeName);
return Registrations.FirstOrDefault(d => d.PluginImplementation.PluginInfo.Guid == pluginGuid && d.LayerEffectDescriptor.LayerEffectType.Name == typeName);
}
}

View File

@ -7,12 +7,12 @@ namespace Artemis.Core
/// </summary>
public class ConditionOperatorRegistration
{
internal ConditionOperatorRegistration(BaseConditionOperator conditionOperator, Plugin plugin)
internal ConditionOperatorRegistration(BaseConditionOperator conditionOperator, PluginImplementation pluginImplementation)
{
ConditionOperator = conditionOperator;
Plugin = plugin;
PluginImplementation = pluginImplementation;
Plugin.PluginDisabled += PluginOnPluginDisabled;
PluginImplementation.Disabled += OnDisabled;
}
/// <summary>
@ -23,16 +23,16 @@ namespace Artemis.Core
/// <summary>
/// Gets the plugin the condition operator is associated with
/// </summary>
public Plugin Plugin { get; }
public PluginImplementation PluginImplementation { get; }
/// <summary>
/// Gets a boolean indicating whether the registration is in the internal Core store
/// </summary>
public bool IsInStore { get; internal set; }
private void PluginOnPluginDisabled(object sender, EventArgs e)
private void OnDisabled(object sender, EventArgs e)
{
Plugin.PluginDisabled -= PluginOnPluginDisabled;
PluginImplementation.Disabled -= OnDisabled;
if (IsInStore)
ConditionOperatorStore.Remove(this);
}

View File

@ -7,12 +7,12 @@ namespace Artemis.Core
/// </summary>
public class DataBindingModifierTypeRegistration
{
internal DataBindingModifierTypeRegistration(BaseDataBindingModifierType dataBindingModifierType, Plugin plugin)
internal DataBindingModifierTypeRegistration(BaseDataBindingModifierType dataBindingModifierType, PluginImplementation pluginImplementation)
{
DataBindingModifierType = dataBindingModifierType;
Plugin = plugin;
PluginImplementation = pluginImplementation;
Plugin.PluginDisabled += PluginOnPluginDisabled;
PluginImplementation.Disabled += OnDisabled;
}
/// <summary>
@ -23,16 +23,16 @@ namespace Artemis.Core
/// <summary>
/// Gets the plugin the data binding modifier is associated with
/// </summary>
public Plugin Plugin { get; }
public PluginImplementation PluginImplementation { get; }
/// <summary>
/// Gets a boolean indicating whether the registration is in the internal Core store
/// </summary>
public bool IsInStore { get; internal set; }
private void PluginOnPluginDisabled(object sender, EventArgs e)
private void OnDisabled(object sender, EventArgs e)
{
Plugin.PluginDisabled -= PluginOnPluginDisabled;
PluginImplementation.Disabled -= OnDisabled;
if (IsInStore)
DataBindingModifierTypeStore.Remove(this);
}

View File

@ -8,12 +8,12 @@ namespace Artemis.Core
/// </summary>
public class DataModelRegistration
{
internal DataModelRegistration(DataModel dataModel, Plugin plugin)
internal DataModelRegistration(DataModel dataModel, PluginImplementation pluginImplementation)
{
DataModel = dataModel;
Plugin = plugin;
PluginImplementation = pluginImplementation;
Plugin.PluginDisabled += PluginOnPluginDisabled;
PluginImplementation.Disabled += OnDisabled;
}
/// <summary>
@ -24,16 +24,16 @@ namespace Artemis.Core
/// <summary>
/// Gets the plugin the data model is associated with
/// </summary>
public Plugin Plugin { get; }
public PluginImplementation PluginImplementation { get; }
/// <summary>
/// Gets a boolean indicating whether the registration is in the internal Core store
/// </summary>
public bool IsInStore { get; internal set; }
private void PluginOnPluginDisabled(object sender, EventArgs e)
private void OnDisabled(object sender, EventArgs e)
{
Plugin.PluginDisabled -= PluginOnPluginDisabled;
PluginImplementation.Disabled -= OnDisabled;
if (IsInStore)
DataModelStore.Remove(this);
}

View File

@ -8,12 +8,12 @@ namespace Artemis.Core
/// </summary>
public class LayerBrushRegistration
{
internal LayerBrushRegistration(LayerBrushDescriptor descriptor, Plugin plugin)
internal LayerBrushRegistration(LayerBrushDescriptor descriptor, PluginImplementation pluginImplementation)
{
LayerBrushDescriptor = descriptor;
Plugin = plugin;
PluginImplementation = pluginImplementation;
Plugin.PluginDisabled += PluginOnPluginDisabled;
PluginImplementation.Disabled += OnDisabled;
}
/// <summary>
@ -24,16 +24,16 @@ namespace Artemis.Core
/// <summary>
/// Gets the plugin the layer brush is associated with
/// </summary>
public Plugin Plugin { get; }
public PluginImplementation PluginImplementation { get; }
/// <summary>
/// Gets a boolean indicating whether the registration is in the internal Core store
/// </summary>
public bool IsInStore { get; internal set; }
private void PluginOnPluginDisabled(object sender, EventArgs e)
private void OnDisabled(object sender, EventArgs e)
{
Plugin.PluginDisabled -= PluginOnPluginDisabled;
PluginImplementation.Disabled -= OnDisabled;
if (IsInStore)
LayerBrushStore.Remove(this);
}

View File

@ -8,12 +8,12 @@ namespace Artemis.Core
/// </summary>
public class LayerEffectRegistration
{
internal LayerEffectRegistration(LayerEffectDescriptor descriptor, Plugin plugin)
internal LayerEffectRegistration(LayerEffectDescriptor descriptor, PluginImplementation pluginImplementation)
{
LayerEffectDescriptor = descriptor;
Plugin = plugin;
PluginImplementation = pluginImplementation;
Plugin.PluginDisabled += PluginOnPluginDisabled;
PluginImplementation.Disabled += OnDisabled;
}
/// <summary>
@ -24,16 +24,16 @@ namespace Artemis.Core
/// <summary>
/// Gets the plugin the layer effect is associated with
/// </summary>
public Plugin Plugin { get; }
public PluginImplementation PluginImplementation { get; }
/// <summary>
/// Gets a boolean indicating whether the registration is in the internal Core store
/// </summary>
public bool IsInStore { get; internal set; }
private void PluginOnPluginDisabled(object sender, EventArgs e)
private void OnDisabled(object sender, EventArgs e)
{
Plugin.PluginDisabled -= PluginOnPluginDisabled;
PluginImplementation.Disabled -= OnDisabled;
if (IsInStore)
LayerEffectStore.Remove(this);
}

View File

@ -5,19 +5,19 @@ namespace Artemis.Core
/// <summary>
/// An empty plugin used by <see cref="Constants.CorePluginInfo"/>
/// </summary>
internal class CorePlugin : Plugin
internal class CorePluginImplementation : PluginImplementation
{
public CorePlugin()
public CorePluginImplementation()
{
Constants.CorePluginInfo.Instance = this;
Enabled = true;
IsEnabled = true;
}
public override void EnablePlugin()
public override void Enable()
{
}
public override void DisablePlugin()
public override void Disable()
{
}
}
@ -26,14 +26,14 @@ namespace Artemis.Core
{
public EffectPlaceholderPlugin()
{
Enabled = true;
IsEnabled = true;
}
public override void EnablePlugin()
public override void Enable()
{
}
public override void DisablePlugin()
public override void Disable()
{
}
}

View File

@ -67,12 +67,12 @@ namespace Artemis.Core
internal class DummyModule : ProfileModule
{
public override void EnablePlugin()
public override void Enable()
{
throw new NotImplementedException();
}
public override void DisablePlugin()
public override void Disable()
{
throw new NotImplementedException();
}

View File

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

View File

@ -16,7 +16,7 @@ namespace Artemis.UI.Shared
ViewModelType = viewModelType;
if (PluginInfo != Constants.CorePluginInfo)
PluginInfo.Instance.PluginDisabled += InstanceOnPluginDisabled;
PluginInfo.Instance.Disabled += InstanceOnDisabled;
}
public PluginInfo PluginInfo { get; }
@ -26,10 +26,10 @@ namespace Artemis.UI.Shared
internal void Unsubscribe()
{
if (PluginInfo != Constants.CorePluginInfo)
PluginInfo.Instance.PluginDisabled -= InstanceOnPluginDisabled;
PluginInfo.Instance.Disabled -= InstanceOnDisabled;
}
private void InstanceOnPluginDisabled(object sender, EventArgs e)
private void InstanceOnDisabled(object sender, EventArgs e)
{
// Profile editor service will call Unsubscribe
_profileEditorService.RemovePropertyInput(this);

View File

@ -42,24 +42,24 @@ namespace Artemis.UI.Shared.Services
return viewModel;
}
public DataModelPropertiesViewModel GetPluginDataModelVisualization(Plugin plugin, bool includeMainDataModel)
public DataModelPropertiesViewModel GetPluginDataModelVisualization(PluginImplementation pluginImplementation, bool includeMainDataModel)
{
if (includeMainDataModel)
{
DataModelPropertiesViewModel mainDataModel = GetMainDataModelVisualization();
// If the main data model already includes the plugin data model we're done
if (mainDataModel.Children.Any(c => c.DataModel.PluginInfo.Instance == plugin))
if (mainDataModel.Children.Any(c => c.DataModel.Implementation.Instance == pluginImplementation))
return mainDataModel;
// Otherwise get just the plugin data model and add it
DataModelPropertiesViewModel pluginDataModel = GetPluginDataModelVisualization(plugin, false);
DataModelPropertiesViewModel pluginDataModel = GetPluginDataModelVisualization(pluginImplementation, false);
if (pluginDataModel != null)
mainDataModel.Children.Add(pluginDataModel);
return mainDataModel;
}
DataModel dataModel = _dataModelService.GetPluginDataModel(plugin);
DataModel dataModel = _dataModelService.GetPluginDataModel(pluginImplementation);
if (dataModel == null)
return null;

View File

@ -109,11 +109,11 @@ namespace Artemis.UI.Shared.Services
private async Task<object> ShowDialogAt<T>(string identifier, IParameter[] parameters) where T : DialogViewModelBase
{
Plugin callingPlugin = _pluginService.GetCallingPlugin();
PluginImplementation callingPluginImplementation = _pluginService.GetCallingPlugin();
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
if (callingPlugin != null)
return await ShowDialog(identifier, callingPlugin.PluginInfo.Kernel.Get<T>(parameters));
if (callingPluginImplementation != null)
return await ShowDialog(identifier, callingPluginImplementation.PluginInfo.Kernel.Get<T>(parameters));
return await ShowDialog(identifier, _kernel.Get<T>(parameters));
}

View File

@ -12,7 +12,7 @@ namespace Artemis.UI.Shared.Services
IReadOnlyCollection<DataModelVisualizationRegistration> RegisteredDataModelEditors { get; }
IReadOnlyCollection<DataModelVisualizationRegistration> RegisteredDataModelDisplays { get; }
DataModelPropertiesViewModel GetMainDataModelVisualization();
DataModelPropertiesViewModel GetPluginDataModelVisualization(Plugin plugin, bool includeMainDataModel);
DataModelPropertiesViewModel GetPluginDataModelVisualization(PluginImplementation pluginImplementation, bool includeMainDataModel);
DataModelVisualizationRegistration RegisterDataModelInput<T>(PluginInfo pluginInfo, IReadOnlyCollection<Type> compatibleConversionTypes) where T : DataModelInputViewModel;
DataModelVisualizationRegistration RegisterDataModelDisplay<T>(PluginInfo pluginInfo) where T : DataModelDisplayViewModel;

View File

@ -35,7 +35,7 @@ namespace Artemis.UI.Ninject.Factories
public interface ISettingsVmFactory : IVmFactory
{
PluginSettingsViewModel CreatePluginSettingsViewModel(Plugin plugin);
PluginSettingsViewModel CreatePluginSettingsViewModel(PluginImplementation pluginImplementation);
DeviceSettingsViewModel CreateDeviceSettingsViewModel(ArtemisDevice device);
}

View File

@ -55,7 +55,7 @@ namespace Artemis.UI.Screens.Settings.Debug
{
try
{
Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Device.Plugin.PluginInfo.Directory.FullName);
Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Device.PluginImplementation.PluginInfo.Directory.FullName);
}
catch (Exception e)
{

View File

@ -117,7 +117,7 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
private void PopulateModules()
{
Modules = _pluginService.GetPluginsOfType<Module>().Where(p => p.Enabled).ToList();
Modules = _pluginService.GetPluginsOfType<Module>().Where(p => p.IsEnabled).ToList();
}
}
}

View File

@ -60,7 +60,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
{
try
{
Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Device.Plugin.PluginInfo.Directory.FullName);
Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", Device.PluginImplementation.PluginInfo.Directory.FullName);
}
catch (Exception e)
{

View File

@ -30,18 +30,18 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
private readonly ISnackbarMessageQueue _snackbarMessageQueue;
private readonly IWindowManager _windowManager;
private bool _enabling;
private Plugin _plugin;
private PluginImplementation _pluginImplementation;
private PluginInfo _pluginInfo;
public PluginSettingsViewModel(Plugin plugin,
public PluginSettingsViewModel(PluginImplementation pluginImplementation,
ILogger logger,
IWindowManager windowManager,
IDialogService dialogService,
IPluginService pluginService,
ISnackbarMessageQueue snackbarMessageQueue)
{
Plugin = plugin;
PluginInfo = plugin.PluginInfo;
PluginImplementation = pluginImplementation;
PluginInfo = pluginImplementation.PluginInfo;
_logger = logger;
_windowManager = windowManager;
@ -50,10 +50,10 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
_snackbarMessageQueue = snackbarMessageQueue;
}
public Plugin Plugin
public PluginImplementation PluginImplementation
{
get => _plugin;
set => SetAndNotify(ref _plugin, value);
get => _pluginImplementation;
set => SetAndNotify(ref _pluginImplementation, value);
}
public PluginInfo PluginInfo
@ -69,20 +69,20 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
}
public PackIconKind Icon => GetIconKind();
public string Type => Plugin.GetType().BaseType?.Name ?? Plugin.GetType().Name;
public bool CanOpenSettings => IsEnabled && Plugin.ConfigurationDialog != null;
public string Type => PluginImplementation.GetType().BaseType?.Name ?? PluginImplementation.GetType().Name;
public bool CanOpenSettings => IsEnabled && PluginImplementation.ConfigurationDialog != null;
public bool DisplayLoadFailed => !Enabling && PluginInfo.LoadException != null;
public bool RequiresRestart => Plugin.Enabled && !PluginInfo.Enabled;
public bool RequiresRestart => PluginImplementation.IsEnabled && !PluginInfo.IsEnabled;
public bool IsEnabled
{
get => Plugin.PluginInfo.Enabled;
get => PluginImplementation.PluginInfo.IsEnabled;
set => Task.Run(() => UpdateEnabled(value));
}
public void OpenSettings()
{
PluginConfigurationDialog configurationViewModel = Plugin.ConfigurationDialog;
PluginConfigurationDialog configurationViewModel = PluginImplementation.ConfigurationDialog;
if (configurationViewModel == null)
return;
@ -93,8 +93,8 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
if (constructors.Length != 1)
throw new ArtemisUIException("Plugin configuration dialogs must have exactly one constructor");
ParameterInfo pluginParameter = constructors.First().GetParameters().First(p => typeof(Plugin).IsAssignableFrom(p.ParameterType));
ConstructorArgument plugin = new ConstructorArgument(pluginParameter.Name, Plugin);
ParameterInfo pluginParameter = constructors.First().GetParameters().First(p => typeof(PluginImplementation).IsAssignableFrom(p.ParameterType));
ConstructorArgument plugin = new ConstructorArgument(pluginParameter.Name, PluginImplementation);
PluginConfigurationViewModel viewModel = (PluginConfigurationViewModel) PluginInfo.Kernel.Get(configurationViewModel.Type, plugin);
_windowManager.ShowDialog(new PluginSettingsWindowViewModel(viewModel, Icon));
}
@ -127,7 +127,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
public async Task Restart()
{
_logger.Debug("Restarting for device provider disable {pluginInfo}", Plugin.PluginInfo);
_logger.Debug("Restarting for device provider disable {pluginInfo}", PluginImplementation.PluginInfo);
// Give the logger a chance to write, might not always be enough but oh well
await Task.Delay(500);
@ -143,7 +143,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
return iconEnum;
}
switch (Plugin)
switch (PluginImplementation)
{
case BaseDataModelExpansion _:
return PackIconKind.TableAdd;
@ -170,7 +170,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
return;
}
if (!enable && Plugin is DeviceProvider)
if (!enable && PluginImplementation is DeviceProvider)
{
await DisableDeviceProvider();
return;
@ -183,7 +183,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
try
{
_pluginService.EnablePlugin(Plugin);
_pluginService.EnablePlugin(PluginImplementation);
}
catch (Exception e)
{
@ -195,7 +195,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
}
}
else
_pluginService.DisablePlugin(Plugin);
_pluginService.DisablePlugin(PluginImplementation);
NotifyOfPropertyChange(nameof(IsEnabled));
NotifyOfPropertyChange(nameof(CanOpenSettings));
@ -208,9 +208,9 @@ 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.Enabled && p.Instance.Enabled);
bool restartQueued = _pluginService.GetAllPluginInfo().Any(p => p.Instance != null && !p.IsEnabled && p.Instance.IsEnabled);
// If the plugin isn't enabled (load failed), it can be disabled without a restart
if (!restartQueued && Plugin.Enabled)
if (!restartQueued && PluginImplementation.IsEnabled)
{
restart = await _dialogService.ShowConfirmDialog(
"Disable device provider",
@ -220,10 +220,10 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
);
}
_pluginService.DisablePlugin(Plugin);
_pluginService.DisablePlugin(PluginImplementation);
if (restart)
{
_logger.Debug("Restarting for device provider disable {pluginInfo}", Plugin.PluginInfo);
_logger.Debug("Restarting for device provider disable {pluginInfo}", PluginImplementation.PluginInfo);
// Give the logger a chance to write, might not always be enough but oh well
await Task.Delay(500);

View File

@ -23,7 +23,7 @@
Identifier="PluginSettingsDialog"
DialogTheme="Inherit">
<DockPanel>
<controls:AppBar Type="Dense" Title="{Binding ActiveItem.Plugin.PluginInfo.Name}" DockPanel.Dock="Top" Margin="-18 0 0 0" ShowShadow="False">
<controls:AppBar Type="Dense" Title="{Binding ActiveItem.PluginImplementation.PluginInfo.Name}" DockPanel.Dock="Top" Margin="-18 0 0 0" ShowShadow="False">
<controls:AppBar.AppIcon>
<materialDesign:PackIcon Kind="{Binding Icon}" Width="20" Height="28" />
</controls:AppBar.AppIcon>