mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Plugins - Separated plugins and implementations as different principles
This commit is contained in:
1 parent
c0d0e421c7
commit
1e0dc1894d
53 files changed
+438
-410
No files matched your search
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-13
@@ -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();
|
||||
}
|
||||
Reference in new issue
Block a user