Plugins - Implemented enabling/disabling (doesnt work for devices)

Plugins - Disable plugins that caused a crash
Tray icon - Added menu items for quick access
This commit is contained in:
SpoinkyNL committed 2020-03-02 22:15:25 +01:00
1 parent 16b221d2f8
commit 57d82fafa8
29 files changed
+442 -164

No files matched your search

@@ -9,11 +9,11 @@ namespace Artemis.Core.Ninject
{
internal class PluginSettingsProvider : Provider<PluginSettings>
{
private readonly IPluginSettingRepository _pluginSettingRepository;
private readonly IPluginRepository _pluginRepository;
internal PluginSettingsProvider(IPluginSettingRepository pluginSettingRepository)
internal PluginSettingsProvider(IPluginRepository pluginRepository)
{
_pluginSettingRepository = pluginSettingRepository;
_pluginRepository = pluginRepository;
}
protected override PluginSettings CreateInstance(IContext context)
@@ -25,7 +25,7 @@ namespace Artemis.Core.Ninject
if (pluginInfo == null)
throw new ArtemisCoreException("A plugin needs to be initialized with PluginInfo as a parameter");
return new PluginSettings(pluginInfo, _pluginSettingRepository);
return new PluginSettings(pluginInfo, _pluginRepository);
}
}
}
@@ -2,6 +2,7 @@
using System.IO;
using System.Reflection;
using Artemis.Core.Plugins.Abstract;
using Artemis.Storage.Entities.Plugins;
using McMaster.NETCore.Plugins;
using Newtonsoft.Json;
@@ -72,6 +73,12 @@ namespace Artemis.Core.Plugins.Models
[JsonIgnore]
internal Assembly Assembly { get; set; }
/// <summary>
/// The entity representing the plugin
/// </summary>
[JsonIgnore]
internal PluginEntity PluginEntity { get; set; }
public override string ToString()
{
return $"{nameof(Guid)}: {Guid}, {nameof(Name)}: {Name}, {nameof(Version)}: {Version}";
@@ -1,5 +1,6 @@
using System;
using Artemis.Storage.Entities;
using Artemis.Storage.Entities.Plugins;
using Artemis.Storage.Repositories.Interfaces;
using Newtonsoft.Json;
@@ -10,13 +11,13 @@ namespace Artemis.Core.Plugins.Models
// ReSharper disable once NotAccessedField.Local
private readonly PluginInfo _pluginInfo;
private readonly PluginSettingEntity _pluginSettingEntity;
private readonly IPluginSettingRepository _pluginSettingRepository;
private readonly IPluginRepository _pluginRepository;
private T _value;
internal PluginSetting(PluginInfo pluginInfo, IPluginSettingRepository pluginSettingRepository, PluginSettingEntity pluginSettingEntity)
internal PluginSetting(PluginInfo pluginInfo, IPluginRepository pluginRepository, PluginSettingEntity pluginSettingEntity)
{
_pluginInfo = pluginInfo;
_pluginSettingRepository = pluginSettingRepository;
_pluginRepository = pluginRepository;
_pluginSettingEntity = pluginSettingEntity;
Name = pluginSettingEntity.Name;
@@ -73,7 +74,7 @@ namespace Artemis.Core.Plugins.Models
return;
_pluginSettingEntity.Value = JsonConvert.SerializeObject(Value);
_pluginSettingRepository.Save(_pluginSettingEntity);
_pluginRepository.SaveSetting(_pluginSettingEntity);
}
public event EventHandler<EventArgs> SettingChanged;
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Artemis.Storage.Entities;
using Artemis.Storage.Entities.Plugins;
using Artemis.Storage.Repositories.Interfaces;
using Newtonsoft.Json;
@@ -12,13 +13,13 @@ namespace Artemis.Core.Plugins.Models
public class PluginSettings
{
private readonly PluginInfo _pluginInfo;
private readonly IPluginSettingRepository _pluginSettingRepository;
private readonly IPluginRepository _pluginRepository;
private readonly Dictionary<string, object> _settingEntities;
internal PluginSettings(PluginInfo pluginInfo, IPluginSettingRepository pluginSettingRepository)
internal PluginSettings(PluginInfo pluginInfo, IPluginRepository pluginRepository)
{
_pluginInfo = pluginInfo;
_pluginSettingRepository = pluginSettingRepository;
_pluginRepository = pluginRepository;
_settingEntities = new Dictionary<string, object>();
}
@@ -37,15 +38,15 @@ namespace Artemis.Core.Plugins.Models
if (_settingEntities.ContainsKey(name))
return (PluginSetting<T>) _settingEntities[name];
// Try to find in database
var settingEntity = _pluginSettingRepository.GetByNameAndPluginGuid(name, _pluginInfo.Guid);
var settingEntity = _pluginRepository.GetSettingByNameAndGuid(name, _pluginInfo.Guid);
// If not found, create a new one
if (settingEntity == null)
{
settingEntity = new PluginSettingEntity {Name = name, PluginGuid = _pluginInfo.Guid, Value = JsonConvert.SerializeObject(defaultValue)};
_pluginSettingRepository.Add(settingEntity);
_pluginRepository.AddSetting(settingEntity);
}
var pluginSetting = new PluginSetting<T>(_pluginInfo, _pluginSettingRepository, settingEntity);
var pluginSetting = new PluginSetting<T>(_pluginInfo, _pluginRepository, settingEntity);
_settingEntities.Add(name, pluginSetting);
return pluginSetting;
}
@@ -42,6 +42,18 @@ namespace Artemis.Core.Services.Interfaces
/// <param name="pluginInfo">The plugin info defining the plugin to unload</param>
void UnloadPlugin(PluginInfo pluginInfo);
/// <summary>
/// Enables the provided plugin
/// </summary>
/// <param name="plugin"></param>
void EnablePlugin(Plugin plugin);
/// <summary>
/// Disables the provided plugin
/// </summary>
/// <param name="plugin"></param>
void DisablePlugin(Plugin plugin);
/// <summary>
/// Finds the plugin info related to the plugin
/// </summary>
+76 -3
View File
@@ -10,6 +10,8 @@ using Artemis.Core.Plugins.Abstract;
using Artemis.Core.Plugins.Exceptions;
using Artemis.Core.Plugins.Models;
using Artemis.Core.Services.Interfaces;
using Artemis.Storage.Entities.Plugins;
using Artemis.Storage.Repositories.Interfaces;
using McMaster.NETCore.Plugins;
using Newtonsoft.Json;
using Ninject;
@@ -27,13 +29,15 @@ namespace Artemis.Core.Services
{
private readonly IKernel _kernel;
private readonly ILogger _logger;
private readonly IPluginRepository _pluginRepository;
private readonly List<PluginInfo> _plugins;
private IKernel _childKernel;
internal PluginService(IKernel kernel, ILogger logger)
internal PluginService(IKernel kernel, ILogger logger, IPluginRepository pluginRepository)
{
_kernel = kernel;
_logger = logger;
_pluginRepository = pluginRepository;
_plugins = new List<PluginInfo>();
// Ensure the plugins directory exists
@@ -146,6 +150,18 @@ namespace Artemis.Core.Services
// Activate plugins after they are all loaded
foreach (var pluginInfo in _plugins.Where(p => p.Enabled))
{
if (!pluginInfo.PluginEntity.LastEnableSuccessful)
{
pluginInfo.Enabled = false;
_logger.Warning("Plugin failed to load last time, disabling it now to avoid instability. Plugin info: {pluginInfo}", pluginInfo);
continue;
}
// Mark this as false until the plugin enabled successfully and save it in case the plugin drags us down into a crash
pluginInfo.PluginEntity.LastEnableSuccessful = false;
_pluginRepository.SavePlugin(pluginInfo.PluginEntity);
var threwException = false;
try
{
pluginInfo.Instance.EnablePlugin();
@@ -153,6 +169,15 @@ namespace Artemis.Core.Services
catch (Exception e)
{
_logger.Warning(new ArtemisPluginException(pluginInfo, "Failed to load enable plugin", e), "Plugin exception");
pluginInfo.Enabled = false;
threwException = true;
}
// We got this far so the plugin enabled and we didn't crash horribly, yay
if (!threwException)
{
pluginInfo.PluginEntity.LastEnableSuccessful = true;
_pluginRepository.SavePlugin(pluginInfo.PluginEntity);
}
OnPluginEnabled(new PluginEventArgs(pluginInfo));
@@ -191,8 +216,13 @@ namespace Artemis.Core.Services
if (_plugins.Contains(pluginInfo))
UnloadPlugin(pluginInfo);
// TODO Just temporarily until settings are in place
pluginInfo.Enabled = true;
var pluginEntity = _pluginRepository.GetPluginByGuid(pluginInfo.Guid);
if (pluginEntity == null)
pluginEntity = new PluginEntity {PluginGuid = pluginInfo.Guid, IsEnabled = true, LastEnableSuccessful = true};
pluginInfo.PluginEntity = pluginEntity;
pluginInfo.Enabled = pluginEntity.IsEnabled;
var mainFile = Path.Combine(pluginInfo.Directory.FullName, pluginInfo.Main);
if (!File.Exists(mainFile))
throw new ArtemisPluginException(pluginInfo, "Couldn't find the plugins main entry at " + mainFile);
@@ -277,6 +307,49 @@ namespace Artemis.Core.Services
}
}
public void EnablePlugin(Plugin plugin)
{
plugin.PluginInfo.Enabled = true;
plugin.PluginInfo.PluginEntity.IsEnabled = true;
plugin.PluginInfo.PluginEntity.LastEnableSuccessful = false;
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
var threwException = false;
try
{
plugin.EnablePlugin();
}
catch (Exception e)
{
_logger.Warning(new ArtemisPluginException(plugin.PluginInfo, "Failed to enable plugin", e), "Plugin exception");
plugin.PluginInfo.Enabled = false;
threwException = true;
}
// We got this far so the plugin enabled and we didn't crash horribly, yay
if (!threwException)
{
plugin.PluginInfo.PluginEntity.LastEnableSuccessful = true;
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
}
OnPluginEnabled(new PluginEventArgs(plugin.PluginInfo));
}
public void DisablePlugin(Plugin plugin)
{
plugin.PluginInfo.Enabled = false;
plugin.PluginInfo.PluginEntity.IsEnabled = false;
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
plugin.DisablePlugin();
// We got this far so the plugin enabled and we didn't crash horribly, yay
_pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity);
OnPluginDisabled(new PluginEventArgs(plugin.PluginInfo));
}
/// <inheritdoc />
public PluginInfo GetPluginInfo(Plugin plugin)
{
+1
View File
@@ -61,6 +61,7 @@ namespace Artemis.Core.Services
catch (Exception e)
{
_logger.Error(e, "Exception during device loading for device provider {deviceProvider}", deviceProvider.GetType().Name);
throw e;
}
if (deviceProvider.Devices == null)
+2 -2
View File
@@ -9,9 +9,9 @@ namespace Artemis.Core.Services
{
private readonly PluginSettings _pluginSettings;
internal SettingsService(IPluginSettingRepository pluginSettingRepository)
internal SettingsService(IPluginRepository pluginRepository)
{
_pluginSettings = new PluginSettings(Constants.CorePluginInfo, pluginSettingRepository);
_pluginSettings = new PluginSettings(Constants.CorePluginInfo, pluginRepository);
}
public PluginSetting<T> GetSetting<T>(string name, T defaultValue = default)