using System;
using System.Threading.Tasks;
namespace Artemis.Core
{
///
/// This is the base plugin type, use the other interfaces such as Module to create plugins
///
public abstract class Plugin : IDisposable
{
///
/// Gets the plugin info related to this plugin
///
public PluginInfo PluginInfo { get; internal set; }
///
/// Gets whether the plugin is enabled
///
public bool Enabled { get; private set; }
///
/// Gets or sets a configuration dialog for this plugin that is accessible in the UI under Settings > Plugins
///
public PluginConfigurationDialog ConfigurationDialog { get; protected set; }
///
public void Dispose()
{
DisablePlugin();
}
///
/// Called when the plugin is activated
///
public abstract void EnablePlugin();
///
/// Called when the plugin is deactivated or when Artemis shuts down
///
public abstract void DisablePlugin();
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
var 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();
}
}
internal virtual void InternalEnablePlugin()
{
EnablePlugin();
}
internal virtual void InternalDisablePlugin()
{
DisablePlugin();
}
#region Events
///
/// Occurs when the plugin is enabled
///
public event EventHandler PluginEnabled;
///
/// Occurs when the plugin is disabled
///
public event EventHandler PluginDisabled;
///
/// Triggers the PluginEnabled event
///
protected virtual void OnPluginEnabled()
{
PluginEnabled?.Invoke(this, EventArgs.Empty);
}
///
/// Triggers the PluginDisabled event
///
protected virtual void OnPluginDisabled()
{
PluginDisabled?.Invoke(this, EventArgs.Empty);
}
#endregion
}
}