Plugins - Implemented features

Core - Removed Stylet dependency for #500
This commit is contained in:
SpoinkyNL committed 2020-11-11 23:53:52 +01:00
1 parent b56966c585
commit e812929215
139 files changed
+1635 -1106

No files matched your search

+3 -3
View File
@@ -40,7 +40,7 @@ namespace Artemis.Core.Services
IRgbService rgbService, ISurfaceService surfaceService, IProfileService profileService, IModuleService moduleService)
{
Kernel = kernel;
Constants.CorePluginInfo.Kernel = kernel;
Constants.CorePlugin.Kernel = kernel;
_logger = logger;
_pluginManagementService = pluginManagementService;
@@ -133,8 +133,8 @@ namespace Artemis.Core.Services
private void UpdatePluginCache()
{
_modules = _pluginManagementService.GetPluginsOfType<Module>().Where(p => p.IsEnabled).ToList();
_dataModelExpansions = _pluginManagementService.GetPluginsOfType<BaseDataModelExpansion>().Where(p => p.IsEnabled).ToList();
_modules = _pluginManagementService.GetFeaturesOfType<Module>().Where(p => p.IsEnabled).ToList();
_dataModelExpansions = _pluginManagementService.GetFeaturesOfType<BaseDataModelExpansion>().Where(p => p.IsEnabled).ToList();
}
private void ConfigureJsonConvert()
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Artemis.Core.DeviceProviders;
using RGB.NET.Core;
namespace Artemis.Core.Services
@@ -33,69 +34,77 @@ namespace Artemis.Core.Services
void UnloadPlugins();
/// <summary>
/// Loads the plugin defined in the provided <see cref="PluginInfo" />
/// Loads the plugin located in the provided <paramref name="directory" />
/// </summary>
/// <param name="pluginInfo">The plugin info defining the plugin to load</param>
void LoadPlugin(DirectoryInfo pluginInfo);
/// <param name="directory">The directory where the plugin is located</param>
Plugin LoadPlugin(DirectoryInfo directory);
/// <summary>
/// Unloads the plugin defined in the provided <see cref="PluginInfo" />
/// Enables the provided <paramref name="plugin" />
/// </summary>
/// <param name="pluginInfo">The plugin info defining the plugin to unload</param>
void UnloadPlugin(PluginInfo pluginInfo);
/// <param name="plugin">The plugin to enable</param>
void EnablePlugin(Plugin plugin, bool ignorePluginLock = false);
/// <summary>
/// Enables the provided plugin
/// Unloads the provided <paramref name="plugin" />
/// </summary>
/// <param name="pluginImplementation"></param>
/// <param name="plugin">The plugin to unload</param>
void UnloadPlugin(Plugin plugin);
/// <summary>
/// Disables the provided <paramref name="plugin" />
/// </summary>
/// <param name="plugin">The plugin to disable</param>
void DisablePlugin(Plugin plugin);
/// <summary>
/// Enables the provided plugin feature
/// </summary>
/// <param name="pluginFeature"></param>
/// <param name="isAutoEnable">If true, fails if there is a lock file present</param>
void EnablePluginImplementation(PluginImplementation pluginImplementation, bool isAutoEnable = false);
void EnablePluginFeature(PluginFeature pluginFeature, bool isAutoEnable = false);
/// <summary>
/// Disables the provided plugin
/// Disables the provided plugin feature
/// </summary>
/// <param name="pluginImplementation"></param>
void DisablePluginImplementation(PluginImplementation pluginImplementation);
/// <summary>
/// Finds the plugin info related to the plugin
/// </summary>
/// <param name="pluginImplementation">The plugin you want to find the plugin info for</param>
/// <returns>The plugins PluginInfo</returns>
PluginInfo GetPluginInfo(PluginImplementation pluginImplementation);
/// <param name="pluginFeature"></param>
void DisablePluginFeature(PluginFeature pluginFeature);
/// <summary>
/// Gets the plugin info of all loaded plugins
/// </summary>
/// <returns>A list containing all the plugin info</returns>
List<PluginInfo> GetAllPluginInfo();
List<Plugin> GetAllPlugins();
/// <summary>
/// Finds all enabled <see cref="PluginImplementation" /> instances of <typeparamref name="T" />
/// Finds all enabled <see cref="PluginFeature" /> instances of <typeparamref name="T" />
/// </summary>
/// <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 : PluginImplementation;
/// <typeparam name="T">
/// Either <see cref="PluginFeature" /> or a plugin type implementing
/// <see cref="PluginFeature" />
/// </typeparam>
/// <returns>Returns a list of feature instances of <typeparamref name="T" /></returns>
List<T> GetFeaturesOfType<T>() where T : PluginFeature;
/// <summary>
/// Gets the plugin that provided the specified assembly
/// </summary>
/// <param name="assembly"></param>
/// <returns></returns>
PluginImplementation GetPluginByAssembly(Assembly assembly);
Plugin GetPluginByAssembly(Assembly assembly);
/// <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();
/// <summary>
/// Gets the plugin that defined the specified device
/// </summary>
/// <param name="device"></param>
/// <returns></returns>
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>
PluginImplementation GetCallingPlugin();
DeviceProvider GetDeviceProviderByDevice(IRGBDevice device);
#region Events
@@ -134,6 +143,26 @@ namespace Artemis.Core.Services
/// </summary>
event EventHandler<PluginEventArgs> PluginDisabled;
/// <summary>
/// Occurs when a plugin feature is being enabled
/// </summary>
public event EventHandler<PluginFeatureEventArgs> PluginFeatureEnabling;
/// <summary>
/// Occurs when a plugin feature has been enabled
/// </summary>
public event EventHandler<PluginFeatureEventArgs> PluginFeatureEnabled;
/// <summary>
/// Occurs when a plugin feature could not be enabled
/// </summary>
public event EventHandler<PluginFeatureEventArgs> PluginFeatureEnableFailed;
/// <summary>
/// Occurs when a plugin feature has been disabled
/// </summary>
public event EventHandler<PluginFeatureEventArgs> PluginFeatureDisabled;
#endregion
}
}
+127 -119
View File
@@ -26,16 +26,129 @@ namespace Artemis.Core.Services
_moduleRepository = moduleRepository;
_pluginManagementService = pluginManagementService;
_profileService = profileService;
_pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementEnabled;
_pluginManagementService.PluginFeatureEnabled += OnPluginFeatureEnabled;
Timer activationUpdateTimer = new Timer(2000);
activationUpdateTimer.Start();
activationUpdateTimer.Elapsed += ActivationUpdateTimerOnElapsed;
foreach (Module module in _pluginManagementService.GetPluginsOfType<Module>())
foreach (Module module in _pluginManagementService.GetFeaturesOfType<Module>())
InitialiseOrApplyPriority(module);
}
private async void ActivationUpdateTimerOnElapsed(object sender, ElapsedEventArgs e)
{
await UpdateModuleActivation();
}
private async Task ActivateModule(Module module)
{
try
{
module.Activate(false);
// If this is a profile module, activate the last active profile after module activation
if (module is ProfileModule profileModule)
await _profileService.ActivateLastProfileAnimated(profileModule);
}
catch (Exception e)
{
_logger.Error(new ArtemisPluginFeatureException(
module, "Failed to activate module and last profile.", e), "Failed to activate module and last profile"
);
throw;
}
}
private async Task DeactivateModule(Module module)
{
try
{
// If this is a profile module, animate profile disable
// module.Deactivate would do the same but without animation
if (module.IsActivated && module is ProfileModule profileModule)
await profileModule.ChangeActiveProfileAnimated(null, null);
module.Deactivate(false);
}
catch (Exception e)
{
_logger.Error(new ArtemisPluginFeatureException(
module, "Failed to deactivate module and last profile.", e), "Failed to deactivate module and last profile"
);
throw;
}
}
private void OverrideActivate(Module module)
{
try
{
if (module.IsActivated)
return;
// If activating while it should be deactivated, its an override
bool shouldBeActivated = module.EvaluateActivationRequirements();
module.Activate(!shouldBeActivated);
// If this is a profile module, activate the last active profile after module activation
if (module is ProfileModule profileModule)
_profileService.ActivateLastProfile(profileModule);
}
catch (Exception e)
{
_logger.Error(new ArtemisPluginFeatureException(
module, "Failed to activate module and last profile.", e), "Failed to activate module and last profile"
);
throw;
}
}
private void OverrideDeactivate(Module module, bool clearingOverride)
{
try
{
if (!module.IsActivated)
return;
// If deactivating while it should be activated, its an override
bool shouldBeActivated = module.EvaluateActivationRequirements();
// No need to deactivate if it is not in an overridden state
if (shouldBeActivated && !module.IsActivatedOverride && !clearingOverride)
return;
module.Deactivate(true);
}
catch (Exception e)
{
_logger.Error(new ArtemisPluginFeatureException(
module, "Failed to deactivate module and last profile.", e), "Failed to deactivate module and last profile"
);
throw;
}
}
private void OnPluginFeatureEnabled(object? sender, PluginFeatureEventArgs e)
{
if (e.PluginFeature is Module module)
InitialiseOrApplyPriority(module);
}
private void InitialiseOrApplyPriority(Module module)
{
ModulePriorityCategory category = module.DefaultPriorityCategory;
int priority = 1;
module.Entity = _moduleRepository.GetByModuleId(module.Id);
if (module.Entity != null)
{
category = (ModulePriorityCategory) module.Entity.PriorityCategory;
priority = module.Entity.Priority;
}
UpdateModulePriority(module, category, priority);
}
public Module ActiveModuleOverride { get; private set; }
public async Task SetActiveModuleOverride(Module overrideModule)
@@ -46,17 +159,19 @@ namespace Artemis.Core.Services
if (ActiveModuleOverride == overrideModule)
return;
if (overrideModule != null)
{
OverrideActivate(overrideModule);
_logger.Information($"Setting active module override to {overrideModule.DisplayName}");
}
else
{
_logger.Information("Clearing active module override");
}
// Always deactivate all other modules whenever override is called
List<Module> modules = _pluginManagementService.GetPluginsOfType<Module>().ToList();
List<Module> modules = _pluginManagementService.GetFeaturesOfType<Module>().ToList();
foreach (Module module in modules.Where(m => m != overrideModule))
OverrideDeactivate(module, overrideModule != null);
@@ -83,13 +198,8 @@ namespace Artemis.Core.Services
// the principle is different for this service but not for the module
bool shouldBeActivated = ActiveModuleOverride.EvaluateActivationRequirements();
if (shouldBeActivated && ActiveModuleOverride.IsActivatedOverride)
{
ActiveModuleOverride.Reactivate(true, false);
}
else if (!shouldBeActivated && !ActiveModuleOverride.IsActivatedOverride)
{
ActiveModuleOverride.Reactivate(false, true);
}
else if (!shouldBeActivated && !ActiveModuleOverride.IsActivatedOverride) ActiveModuleOverride.Reactivate(false, true);
return;
}
@@ -97,10 +207,9 @@ namespace Artemis.Core.Services
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
List<Module> modules = _pluginManagementService.GetPluginsOfType<Module>().ToList();
List<Module> modules = _pluginManagementService.GetFeaturesOfType<Module>().ToList();
List<Task> tasks = new List<Task>();
foreach (Module module in modules)
{
lock (module)
{
bool shouldBeActivated = module.EvaluateActivationRequirements() && module.IsEnabled;
@@ -109,7 +218,6 @@ namespace Artemis.Core.Services
else if (!shouldBeActivated && module.IsActivated)
tasks.Add(DeactivateModule(module));
}
}
await Task.WhenAll(tasks);
@@ -128,7 +236,12 @@ namespace Artemis.Core.Services
if (module.PriorityCategory == category && module.Priority == priority)
return;
List<Module> modules = _pluginManagementService.GetPluginsOfType<Module>().Where(m => m.PriorityCategory == category).OrderBy(m => m.Priority).ToList();
List<Module> modules = _pluginManagementService
.GetFeaturesOfType<Module>()
.Where(m => m.PriorityCategory == category)
.OrderBy(m => m.Priority)
.ToList();
if (modules.Contains(module))
modules.Remove(module);
@@ -149,110 +262,5 @@ namespace Artemis.Core.Services
}
}
}
private async void ActivationUpdateTimerOnElapsed(object sender, ElapsedEventArgs e)
{
await UpdateModuleActivation();
}
private async Task ActivateModule(Module module)
{
try
{
module.Activate(false);
// If this is a profile module, activate the last active profile after module activation
if (module is ProfileModule profileModule)
await _profileService.ActivateLastProfileAnimated(profileModule);
}
catch (Exception e)
{
_logger.Error(new ArtemisPluginException(module.PluginInfo, "Failed to activate module and last profile.", e), "Failed to activate module and last profile");
throw;
}
}
private async Task DeactivateModule(Module module)
{
try
{
// If this is a profile module, animate profile disable
// module.Deactivate would do the same but without animation
if (module.IsActivated && module is ProfileModule profileModule)
await profileModule.ChangeActiveProfileAnimated(null, null);
module.Deactivate(false);
}
catch (Exception e)
{
_logger.Error(new ArtemisPluginException(module.PluginInfo, "Failed to deactivate module and last profile.", e), "Failed to deactivate module and last profile");
throw;
}
}
private void OverrideActivate(Module module)
{
try
{
if (module.IsActivated)
return;
// If activating while it should be deactivated, its an override
bool shouldBeActivated = module.EvaluateActivationRequirements();
module.Activate(!shouldBeActivated);
// If this is a profile module, activate the last active profile after module activation
if (module is ProfileModule profileModule)
_profileService.ActivateLastProfile(profileModule);
}
catch (Exception e)
{
_logger.Error(new ArtemisPluginException(module.PluginInfo, "Failed to activate module and last profile.", e), "Failed to activate module and last profile");
throw;
}
}
private void OverrideDeactivate(Module module, bool clearingOverride)
{
try
{
if (!module.IsActivated)
return;
// If deactivating while it should be activated, its an override
bool shouldBeActivated = module.EvaluateActivationRequirements();
// No need to deactivate if it is not in an overridden state
if (shouldBeActivated && !module.IsActivatedOverride && !clearingOverride)
return;
module.Deactivate(true);
}
catch (Exception e)
{
_logger.Error(new ArtemisPluginException(module.PluginInfo, "Failed to deactivate module and last profile.", e), "Failed to deactivate module and last profile");
throw;
}
}
private void PluginManagementServiceOnPluginManagementEnabled(object sender, PluginEventArgs e)
{
if (e.PluginInfo.Plugin is Module module)
InitialiseOrApplyPriority(module);
}
private void InitialiseOrApplyPriority(Module module)
{
ModulePriorityCategory category = module.DefaultPriorityCategory;
int priority = 1;
module.Entity = _moduleRepository.GetByPluginGuid(module.PluginInfo.Guid);
if (module.Entity != null)
{
category = (ModulePriorityCategory) module.Entity.PriorityCategory;
priority = module.Entity.Priority;
}
UpdateModulePriority(module, category, priority);
}
}
}
@@ -41,6 +41,21 @@ namespace Artemis.Core.Services
Directory.CreateDirectory(Constants.DataFolder + "plugins");
}
private void CopyBuiltInPlugin(FileInfo zipFileInfo, ZipArchive zipArchive)
{
DirectoryInfo pluginDirectory = new DirectoryInfo(Path.Combine(Constants.DataFolder, "plugins", Path.GetFileNameWithoutExtension(zipFileInfo.Name)));
bool createLockFile = File.Exists(Path.Combine(pluginDirectory.FullName, "artemis.lock"));
// Remove the old directory if it exists
if (Directory.Exists(pluginDirectory.FullName))
pluginDirectory.DeleteRecursively();
Directory.CreateDirectory(pluginDirectory.FullName);
zipArchive.ExtractToDirectory(pluginDirectory.FullName, true);
if (createLockFile)
File.Create(Path.Combine(pluginDirectory.FullName, "artemis.lock")).Close();
}
public bool LoadingPlugins { get; private set; }
#region Built in plugins
@@ -72,7 +87,9 @@ namespace Artemis.Core.Services
// Find the matching plugin in the plugin folder
DirectoryInfo? match = pluginDirectory.EnumerateDirectories().FirstOrDefault(d => d.Name == Path.GetFileNameWithoutExtension(zipFile.Name));
if (match == null)
{
CopyBuiltInPlugin(zipFile, archive);
}
else
{
string metadataFile = Path.Combine(match.FullName, "plugin.json");
@@ -105,6 +122,48 @@ namespace Artemis.Core.Services
#endregion
public List<Plugin> GetAllPlugins()
{
return new List<Plugin>(_plugins);
}
public List<T> GetFeaturesOfType<T>() where T : PluginFeature
{
return _plugins.Where(p => p.IsEnabled).SelectMany(p => p.Features.Where(i => i.IsEnabled && i is T)).Cast<T>().ToList();
}
public Plugin? GetPluginByAssembly(Assembly assembly)
{
return _plugins.FirstOrDefault(p => p.Assembly == assembly);
}
// TODO: move to a more appropriate service
public DeviceProvider GetDeviceProviderByDevice(IRGBDevice rgbDevice)
{
return GetFeaturesOfType<DeviceProvider>().First(d => d.RgbDeviceProvider.Devices != null && d.RgbDeviceProvider.Devices.Contains(rgbDevice));
}
public Plugin? GetCallingPlugin()
{
StackTrace stackTrace = new StackTrace(); // get call stack
StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames)
foreach (StackFrame stackFrame in stackFrames)
{
Assembly assembly = stackFrame.GetMethod().DeclaringType.Assembly;
Plugin plugin = GetPluginByAssembly(assembly);
if (plugin != null)
return plugin;
}
return null;
}
public void Dispose()
{
UnloadPlugins();
}
#region Plugins
public void LoadPlugins(bool ignorePluginLock)
@@ -125,7 +184,8 @@ namespace Artemis.Core.Services
{
try
{
LoadPlugin(subDirectory);
Plugin plugin = LoadPlugin(subDirectory);
EnablePlugin(plugin, ignorePluginLock);
}
catch (Exception e)
{
@@ -133,22 +193,6 @@ namespace Artemis.Core.Services
}
}
// Activate plugins after they are all loaded
foreach (Plugin plugin in _plugins.Where(p => p.Entity.IsEnabled))
{
foreach (PluginImplementation pluginImplementation in plugin.Implementations.Where(i => i.Entity.IsEnabled))
{
try
{
EnablePluginImplementation(pluginImplementation, !ignorePluginLock);
}
catch (Exception)
{
// ignored, logged in EnablePlugin
}
}
}
LoadingPlugins = false;
}
}
@@ -165,29 +209,32 @@ namespace Artemis.Core.Services
}
}
public void LoadPlugin(DirectoryInfo pluginDirectory)
public Plugin LoadPlugin(DirectoryInfo directory)
{
lock (_plugins)
{
_logger.Debug("Loading plugin from {directory}", pluginDirectory.FullName);
_logger.Debug("Loading plugin from {directory}", directory.FullName);
// Load the metadata
string metadataFile = Path.Combine(pluginDirectory.FullName, "plugin.json");
string metadataFile = Path.Combine(directory.FullName, "plugin.json");
if (!File.Exists(metadataFile))
_logger.Warning(new ArtemisPluginException("Couldn't find the plugins metadata file at " + metadataFile), "Plugin exception");
// PluginInfo contains the ID which we need to move on
PluginInfo pluginInfo = JsonConvert.DeserializeObject<PluginInfo>(File.ReadAllText(metadataFile));
if (pluginInfo.Guid == Constants.CorePluginInfo.Guid)
throw new ArtemisPluginException($"Plugin cannot use reserved GUID {pluginInfo.Guid}");
// Ensure the plugin is not already loaded
if (_plugins.Any(p => p.Guid == pluginInfo.Guid))
throw new ArtemisCoreException("Cannot load a plugin that is already loaded");
Plugin plugin = new Plugin(pluginInfo, pluginDirectory);
Plugin plugin = new Plugin(pluginInfo, directory);
OnPluginLoading(new PluginEventArgs(plugin));
// Load the entity and fall back on creating a new one
plugin.Entity = _pluginRepository.GetPluginByGuid(pluginInfo.Guid) ?? new PluginEntity { Id = plugin.Guid, IsEnabled = true };
plugin.Entity = _pluginRepository.GetPluginByGuid(pluginInfo.Guid) ?? new PluginEntity {Id = plugin.Guid, IsEnabled = true};
// Locate the main assembly entry
string? mainFile = plugin.ResolveRelativePath(plugin.Info.Main);
@@ -210,55 +257,94 @@ namespace Artemis.Core.Services
throw new ArtemisPluginException(plugin, "Failed to load the plugins assembly", e);
}
// Get the Plugin implementation from the main assembly and if there is only one, instantiate it
List<Type> implementationTypes;
try
{
implementationTypes = plugin.Assembly.GetTypes().Where(t => typeof(PluginImplementation).IsAssignableFrom(t)).ToList();
}
catch (ReflectionTypeLoadException e)
{
throw new ArtemisPluginException(plugin, "Failed to initialize the plugin assembly", new AggregateException(e.LoaderExceptions));
}
// Create the Ninject child kernel and load the module
plugin.Kernel = new ChildKernel(_kernel);
plugin.Kernel.Load(new PluginModule(pluginInfo));
if (!implementationTypes.Any())
_logger.Warning("Plugin {plugin} contains no implementations", plugin);
// Create instances of each implementation and add them to the plugin
// Construction should be simple and not contain any logic so failure at this point means the entire plugin fails
foreach (Type implementationType in implementationTypes)
{
try
{
PluginImplementation instance = (PluginImplementation)plugin.Kernel.Get(implementationType);
plugin.AddImplementation(instance);
}
catch (Exception e)
{
throw new ArtemisPluginException(plugin, "Failed to load instantiate implementation", e);
}
}
List<Type> bootstrappers = plugin.Assembly.GetTypes().Where(t => typeof(IPluginBootstrapper).IsAssignableFrom(t)).ToList();
if (bootstrappers.Count > 1)
_logger.Warning($"{plugin} has more than one bootstrapper, only initializing {bootstrappers.First().FullName}");
if (bootstrappers.Any())
plugin.Bootstrapper = (IPluginBootstrapper?) Activator.CreateInstance(bootstrappers.First());
_plugins.Add(plugin);
OnPluginLoaded(new PluginEventArgs(plugin));
return plugin;
}
}
public void EnablePlugin(Plugin plugin, bool ignorePluginLock)
{
if (plugin.Assembly == null)
throw new ArtemisPluginException(plugin, "Cannot enable a plugin that hasn't successfully been loaded");
// Create the Ninject child kernel and load the module
plugin.Kernel = new ChildKernel(_kernel);
plugin.Kernel.Bind<Plugin>().ToConstant(plugin);
plugin.Kernel.Load(new PluginModule(plugin.Info));
plugin.SetEnabled(true);
// Get the Plugin feature from the main assembly and if there is only one, instantiate it
List<Type> featureTypes;
try
{
featureTypes = plugin.Assembly.GetTypes().Where(t => typeof(PluginFeature).IsAssignableFrom(t)).ToList();
}
catch (ReflectionTypeLoadException e)
{
throw new ArtemisPluginException(plugin, "Failed to initialize the plugin assembly", new AggregateException(e.LoaderExceptions));
}
if (!featureTypes.Any())
_logger.Warning("Plugin {plugin} contains no features", plugin);
// Create instances of each feature and add them to the plugin
// Construction should be simple and not contain any logic so failure at this point means the entire plugin fails
foreach (Type featureType in featureTypes)
{
try
{
// Include Plugin as a parameter for the PluginSettingsProvider
IParameter[] parameters = {new Parameter("Plugin", plugin, false)};
PluginFeature instance = (PluginFeature) plugin.Kernel.Get(featureType, parameters);
plugin.AddFeature(instance);
// Load the enabled state and if not found, default to true
instance.Entity = plugin.Entity.Features.FirstOrDefault(i => i.Type == featureType.FullName) ??
new PluginFeatureEntity {IsEnabled = true, Type = featureType.FullName};
}
catch (Exception e)
{
throw new ArtemisPluginException(plugin, "Failed to load instantiate feature", e);
}
}
// Activate plugins after they are all loaded
foreach (PluginFeature pluginFeature in plugin.Features.Where(i => i.Entity.IsEnabled))
{
try
{
EnablePluginFeature(pluginFeature, !ignorePluginLock);
}
catch (Exception)
{
// ignored, logged in EnablePluginFeature
}
}
OnPluginEnabled(new PluginEventArgs(plugin));
}
public void UnloadPlugin(Plugin plugin)
{
lock (_plugins)
{
try
{
plugin.SetEnabled(false);
DisablePlugin(plugin);
}
catch (Exception)
catch (Exception e)
{
// TODO: Log these
_logger.Warning(new ArtemisPluginException(plugin, "Exception during DisablePlugin call for UnloadPlugin", e), "Failed to unload plugin");
}
finally
{
@@ -267,38 +353,59 @@ namespace Artemis.Core.Services
plugin.Dispose();
_plugins.Remove(plugin);
OnPluginUnloaded(new PluginEventArgs(plugin));
}
}
public void DisablePlugin(Plugin plugin)
{
if (!plugin.IsEnabled)
return;
while (plugin.Features.Any())
{
PluginFeature feature = plugin.Features[0];
plugin.RemoveFeature(feature);
OnPluginFeatureDisabled(new PluginFeatureEventArgs(feature));
}
plugin.SetEnabled(false);
plugin.Kernel.Dispose();
plugin.Kernel = null;
OnPluginDisabled(new PluginEventArgs(plugin));
}
#endregion
#region Features
#region Implementations
public void EnablePluginImplementation(PluginImplementation pluginImplementation, bool isAutoEnable = false)
public void EnablePluginFeature(PluginFeature pluginFeature, bool isAutoEnable = false)
{
_logger.Debug("Enabling plugin implementation {implementation} - {plugin}", pluginImplementation, pluginImplementation.Plugin);
_logger.Debug("Enabling plugin feature {feature} - {plugin}", pluginFeature, pluginFeature.Plugin);
lock (_plugins)
{
OnPluginFeatureEnabling(new PluginFeatureEventArgs(pluginFeature));
try
{
// A device provider may be queued for disable on next restart, this undoes that
if (pluginImplementation is DeviceProvider && pluginImplementation.IsEnabled && !pluginImplementation.PluginInfo.IsEnabled)
if (pluginFeature is DeviceProvider && pluginFeature.IsEnabled && !pluginFeature.Entity.IsEnabled)
{
pluginImplementation.PluginInfo.IsEnabled = true;
pluginImplementation.PluginInfo.ApplyToEntity();
_pluginRepository.SavePlugin(pluginImplementation.PluginInfo.PluginEntity);
pluginFeature.Entity.IsEnabled = true;
SavePlugin(pluginFeature.Plugin);
return;
}
pluginImplementation.SetEnabled(true, isAutoEnable);
pluginFeature.SetEnabled(true, isAutoEnable);
pluginFeature.Entity.IsEnabled = true;
}
catch (Exception e)
{
_logger.Warning(new ArtemisPluginException(pluginImplementation.PluginInfo, "Exception during SetEnabled(true)", e), "Failed to enable plugin");
_logger.Warning(
new ArtemisPluginException(pluginFeature.Plugin, $"Exception during SetEnabled(true) on {pluginFeature}", e),
"Failed to enable plugin"
);
throw;
}
finally
@@ -306,108 +413,83 @@ 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)
pluginImplementation.PluginInfo.IsEnabled = true;
pluginFeature.Entity.IsEnabled = true;
pluginImplementation.PluginInfo.ApplyToEntity();
_pluginRepository.SavePlugin(pluginImplementation.PluginInfo.PluginEntity);
SavePlugin(pluginFeature.Plugin);
if (pluginImplementation.PluginInfo.IsEnabled)
_logger.Debug("Successfully enabled plugin {pluginInfo}", pluginImplementation.PluginInfo);
if (pluginFeature.IsEnabled)
{
_logger.Debug("Successfully enabled plugin feature {feature} - {plugin}", pluginFeature, pluginFeature.Plugin);
OnPluginFeatureEnabled(new PluginFeatureEventArgs(pluginFeature));
}
else
{
OnPluginFeatureEnableFailed(new PluginFeatureEventArgs(pluginFeature));
}
}
}
OnPluginImplementationEnabled(new PluginImplementationEventArgs(pluginImplementation));
}
public void DisablePluginImplementation(PluginImplementation pluginImplementation)
public void DisablePluginFeature(PluginFeature pluginFeature)
{
lock (_plugins)
{
_logger.Debug("Disabling plugin {pluginInfo}", pluginImplementation.PluginInfo);
// Device providers cannot be disabled at runtime simply queue a disable for next restart
if (pluginImplementation is DeviceProvider)
try
{
// Don't call SetEnabled(false) but simply update enabled state and save it
pluginImplementation.PluginInfo.IsEnabled = false;
pluginImplementation.PluginInfo.ApplyToEntity();
_pluginRepository.SavePlugin(pluginImplementation.PluginInfo.PluginEntity);
return;
_logger.Debug("Disabling plugin feature {feature} - {plugin}", pluginFeature, pluginFeature.Plugin);
// Device providers cannot be disabled at runtime simply queue a disable for next restart
if (pluginFeature is DeviceProvider)
{
// Don't call SetEnabled(false) but simply update enabled state and save it
pluginFeature.Entity.IsEnabled = false;
SavePlugin(pluginFeature.Plugin);
return;
}
pluginFeature.SetEnabled(false);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
finally
{
pluginFeature.Entity.IsEnabled = false;
SavePlugin(pluginFeature.Plugin);
pluginImplementation.SetEnabled(false);
pluginImplementation.PluginInfo.ApplyToEntity();
_pluginRepository.SavePlugin(pluginImplementation.PluginInfo.PluginEntity);
_logger.Debug("Successfully disabled plugin {pluginInfo}", pluginImplementation.PluginInfo);
if (!pluginFeature.IsEnabled)
{
_logger.Debug("Successfully disabled plugin feature {feature} - {plugin}", pluginFeature, pluginFeature.Plugin);
OnPluginFeatureDisabled(new PluginFeatureEventArgs(pluginFeature));
}
}
}
OnPluginDisabled(new PluginEventArgs(pluginImplementation.PluginInfo));
}
#endregion
#region Storage
public PluginInfo GetPluginInfo(PluginImplementation pluginImplementation)
private void SavePlugin(Plugin plugin)
{
return _plugins.FirstOrDefault(p => p.Plugin == pluginImplementation);
}
public List<PluginInfo> GetAllPluginInfo()
{
return new List<PluginInfo>(_plugins);
}
public List<T> GetPluginsOfType<T>() where T : PluginImplementation
{
return _plugins.Where(p => p.IsEnabled && p.Plugin is T).Select(p => (T) p.Plugin).ToList();
}
public PluginImplementation GetPluginByAssembly(Assembly assembly)
{
return _plugins.FirstOrDefault(p => p.Assembly == assembly)?.Plugin;
}
public PluginImplementation GetPluginByDevice(IRGBDevice rgbDevice)
{
return GetPluginsOfType<DeviceProvider>().First(d => d.RgbDeviceProvider.Devices != null && d.RgbDeviceProvider.Devices.Contains(rgbDevice));
}
public PluginImplementation GetCallingPlugin()
{
StackTrace stackTrace = new StackTrace(); // get call stack
StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames)
foreach (StackFrame stackFrame in stackFrames)
foreach (PluginFeature pluginFeature in plugin.Features)
{
Assembly assembly = stackFrame.GetMethod().DeclaringType.Assembly;
PluginImplementation pluginImplementation = GetPluginByAssembly(assembly);
if (pluginImplementation != null)
return pluginImplementation;
if (plugin.Entity.Features.All(i => i.Type != pluginFeature.GetType().FullName))
plugin.Entity.Features.Add(pluginFeature.Entity);
}
return null;
_pluginRepository.SavePlugin(plugin.Entity);
}
public void Dispose()
private PluginFeatureEntity GetOrCreateFeatureEntity(PluginFeature feature)
{
UnloadPlugins();
return feature.Plugin.Entity.Features.FirstOrDefault(i => i.Type == feature.GetType().FullName) ??
new PluginFeatureEntity {IsEnabled = true, Type = feature.GetType().FullName};
}
private void CopyBuiltInPlugin(FileInfo zipFileInfo, ZipArchive zipArchive)
{
DirectoryInfo pluginDirectory = new DirectoryInfo(Path.Combine(Constants.DataFolder, "plugins", Path.GetFileNameWithoutExtension(zipFileInfo.Name)));
bool createLockFile = File.Exists(Path.Combine(pluginDirectory.FullName, "artemis.lock"));
// Remove the old directory if it exists
if (Directory.Exists(pluginDirectory.FullName))
pluginDirectory.DeleteRecursively();
Directory.CreateDirectory(pluginDirectory.FullName);
zipArchive.ExtractToDirectory(pluginDirectory.FullName, true);
if (createLockFile)
File.Create(Path.Combine(pluginDirectory.FullName, "artemis.lock")).Close();
}
#endregion
#region Events
@@ -419,8 +501,10 @@ namespace Artemis.Core.Services
public event EventHandler<PluginEventArgs> PluginEnabled;
public event EventHandler<PluginEventArgs> PluginDisabled;
public event EventHandler<PluginImplementationEventArgs> PluginImplementationEnabled;
public event EventHandler<PluginImplementationEventArgs> PluginImplementationDisabled;
public event EventHandler<PluginFeatureEventArgs> PluginFeatureEnabling;
public event EventHandler<PluginFeatureEventArgs> PluginFeatureEnabled;
public event EventHandler<PluginFeatureEventArgs> PluginFeatureDisabled;
public event EventHandler<PluginFeatureEventArgs> PluginFeatureEnableFailed;
protected virtual void OnCopyingBuildInPlugins()
{
@@ -457,14 +541,24 @@ namespace Artemis.Core.Services
PluginDisabled?.Invoke(this, e);
}
protected virtual void OnPluginImplementationDisabled(PluginImplementationEventArgs e)
protected virtual void OnPluginFeatureEnabling(PluginFeatureEventArgs e)
{
PluginImplementationDisabled?.Invoke(this, e);
PluginFeatureEnabling?.Invoke(this, e);
}
protected virtual void OnPluginImplementationEnabled(PluginImplementationEventArgs e)
protected virtual void OnPluginFeatureEnabled(PluginFeatureEventArgs e)
{
PluginImplementationEnabled?.Invoke(this, e);
PluginFeatureEnabled?.Invoke(this, e);
}
protected virtual void OnPluginFeatureDisabled(PluginFeatureEventArgs e)
{
PluginFeatureDisabled?.Invoke(this, e);
}
protected virtual void OnPluginFeatureEnableFailed(PluginFeatureEventArgs e)
{
PluginFeatureEnableFailed?.Invoke(this, e);
}
#endregion
@@ -12,14 +12,14 @@ namespace Artemis.Core.Services
RegisterBuiltInConditionOperators();
}
public ConditionOperatorRegistration RegisterConditionOperator(PluginInfo pluginInfo, BaseConditionOperator conditionOperator)
public ConditionOperatorRegistration RegisterConditionOperator(Plugin plugin, BaseConditionOperator conditionOperator)
{
if (pluginInfo == null)
throw new ArgumentNullException(nameof(pluginInfo));
if (plugin == null)
throw new ArgumentNullException(nameof(plugin));
if (conditionOperator == null)
throw new ArgumentNullException(nameof(conditionOperator));
conditionOperator.PluginInfo = pluginInfo;
conditionOperator.Plugin = plugin;
return ConditionOperatorStore.Add(conditionOperator);
}
@@ -43,30 +43,30 @@ namespace Artemis.Core.Services
private void RegisterBuiltInConditionOperators()
{
// General usage for any type
RegisterConditionOperator(Constants.CorePluginInfo, new EqualsConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new NotEqualConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new EqualsConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new NotEqualConditionOperator());
// Numeric operators
RegisterConditionOperator(Constants.CorePluginInfo, new NumberEqualsConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new NumberNotEqualConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new LessThanConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new LessThanOrEqualConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanOrEqualConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new NumberEqualsConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new NumberNotEqualConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new LessThanConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new GreaterThanConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new LessThanOrEqualConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new GreaterThanOrEqualConditionOperator());
// String operators
RegisterConditionOperator(Constants.CorePluginInfo, new StringEqualsConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringNotEqualConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringContainsConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringNotContainsConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringStartsWithConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringEndsWithConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringMatchesRegexConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new StringEqualsConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new StringNotEqualConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new StringContainsConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new StringNotContainsConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new StringStartsWithConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new StringEndsWithConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new StringMatchesRegexConditionOperator());
// Null checks, at the bottom
// TODO: Implement a priority mechanism
RegisterConditionOperator(Constants.CorePluginInfo, new NullConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new NotNullConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new NullConditionOperator());
RegisterConditionOperator(Constants.CorePlugin, new NotNullConditionOperator());
}
}
}
@@ -12,14 +12,14 @@ namespace Artemis.Core.Services
RegisterBuiltInModifiers();
}
public DataBindingModifierTypeRegistration RegisterModifierType(PluginInfo pluginInfo, BaseDataBindingModifierType dataBindingModifierType)
public DataBindingModifierTypeRegistration RegisterModifierType(Plugin plugin, BaseDataBindingModifierType dataBindingModifierType)
{
if (pluginInfo == null)
throw new ArgumentNullException(nameof(pluginInfo));
if (plugin == null)
throw new ArgumentNullException(nameof(plugin));
if (dataBindingModifierType == null)
throw new ArgumentNullException(nameof(dataBindingModifierType));
dataBindingModifierType.PluginInfo = pluginInfo;
dataBindingModifierType.Plugin = plugin;
return DataBindingModifierTypeStore.Add(dataBindingModifierType);
}
@@ -43,41 +43,41 @@ namespace Artemis.Core.Services
private void RegisterBuiltInModifiers()
{
// Numbers - General
RegisterModifierType(Constants.CorePluginInfo, new SumModifierType());
RegisterModifierType(Constants.CorePluginInfo, new SubtractModifierType());
RegisterModifierType(Constants.CorePluginInfo, new MultiplicationModifierType());
RegisterModifierType(Constants.CorePluginInfo, new DivideModifierType());
RegisterModifierType(Constants.CorePluginInfo, new PercentageOfModifierType());
RegisterModifierType(Constants.CorePlugin, new SumModifierType());
RegisterModifierType(Constants.CorePlugin, new SubtractModifierType());
RegisterModifierType(Constants.CorePlugin, new MultiplicationModifierType());
RegisterModifierType(Constants.CorePlugin, new DivideModifierType());
RegisterModifierType(Constants.CorePlugin, new PercentageOfModifierType());
// Numbers - Advanced
RegisterModifierType(Constants.CorePluginInfo, new MaxModifierType());
RegisterModifierType(Constants.CorePluginInfo, new MinModifierType());
RegisterModifierType(Constants.CorePluginInfo, new ModuloModifierType());
RegisterModifierType(Constants.CorePluginInfo, new AbsoluteModifierType());
RegisterModifierType(Constants.CorePluginInfo, new PowerModifierType());
RegisterModifierType(Constants.CorePluginInfo, new SquareRootModifierType());
RegisterModifierType(Constants.CorePlugin, new MaxModifierType());
RegisterModifierType(Constants.CorePlugin, new MinModifierType());
RegisterModifierType(Constants.CorePlugin, new ModuloModifierType());
RegisterModifierType(Constants.CorePlugin, new AbsoluteModifierType());
RegisterModifierType(Constants.CorePlugin, new PowerModifierType());
RegisterModifierType(Constants.CorePlugin, new SquareRootModifierType());
// Numbers - Rounding
RegisterModifierType(Constants.CorePluginInfo, new FloorModifierType());
RegisterModifierType(Constants.CorePluginInfo, new RoundModifierType());
RegisterModifierType(Constants.CorePluginInfo, new CeilingModifierType());
RegisterModifierType(Constants.CorePlugin, new FloorModifierType());
RegisterModifierType(Constants.CorePlugin, new RoundModifierType());
RegisterModifierType(Constants.CorePlugin, new CeilingModifierType());
// Numbers - Trigonometric
RegisterModifierType(Constants.CorePluginInfo, new SineModifierType());
RegisterModifierType(Constants.CorePluginInfo, new CosineModifierType());
RegisterModifierType(Constants.CorePluginInfo, new TangentModifierType());
RegisterModifierType(Constants.CorePluginInfo, new CotangentModifierType());
RegisterModifierType(Constants.CorePluginInfo, new SecantModifierType());
RegisterModifierType(Constants.CorePluginInfo, new CosecantModifierType());
RegisterModifierType(Constants.CorePlugin, new SineModifierType());
RegisterModifierType(Constants.CorePlugin, new CosineModifierType());
RegisterModifierType(Constants.CorePlugin, new TangentModifierType());
RegisterModifierType(Constants.CorePlugin, new CotangentModifierType());
RegisterModifierType(Constants.CorePlugin, new SecantModifierType());
RegisterModifierType(Constants.CorePlugin, new CosecantModifierType());
// Colors
RegisterModifierType(Constants.CorePluginInfo, new SKColorSumModifierType());
RegisterModifierType(Constants.CorePluginInfo, new SKColorSaturateModifierType());
RegisterModifierType(Constants.CorePluginInfo, new SKColorDesaturateModifierType());
RegisterModifierType(Constants.CorePluginInfo, new SKColorBrightenModifierType());
RegisterModifierType(Constants.CorePluginInfo, new SKColorDarkenModifierType());
RegisterModifierType(Constants.CorePluginInfo, new SKColorRotateHueModifierType());
RegisterModifierType(Constants.CorePluginInfo, new SKColorInvertModifierType());
RegisterModifierType(Constants.CorePlugin, new SKColorSumModifierType());
RegisterModifierType(Constants.CorePlugin, new SKColorSaturateModifierType());
RegisterModifierType(Constants.CorePlugin, new SKColorDesaturateModifierType());
RegisterModifierType(Constants.CorePlugin, new SKColorBrightenModifierType());
RegisterModifierType(Constants.CorePlugin, new SKColorDarkenModifierType());
RegisterModifierType(Constants.CorePlugin, new SKColorRotateHueModifierType());
RegisterModifierType(Constants.CorePlugin, new SKColorInvertModifierType());
}
}
}
@@ -11,15 +11,16 @@ namespace Artemis.Core.Services
public DataModelService(IPluginManagementService pluginManagementService)
{
// Add data models of already loaded plugins
foreach (Module module in pluginManagementService.GetPluginsOfType<Module>().Where(p => p.IsEnabled))
foreach (Module module in pluginManagementService.GetFeaturesOfType<Module>().Where(p => p.IsEnabled))
AddModuleDataModel(module);
foreach (BaseDataModelExpansion dataModelExpansion in pluginManagementService.GetPluginsOfType<BaseDataModelExpansion>().Where(p => p.IsEnabled))
foreach (BaseDataModelExpansion dataModelExpansion in pluginManagementService.GetFeaturesOfType<BaseDataModelExpansion>().Where(p => p.IsEnabled))
AddDataModelExpansionDataModel(dataModelExpansion);
// Add data models of new plugins when they get enabled
pluginManagementService.PluginEnabled += PluginServiceOnPluginEnabled;
pluginManagementService.PluginFeatureEnabled += OnPluginFeatureEnabled;
}
public DataModelRegistration RegisterDataModel(DataModel dataModel)
{
if (dataModel == null)
@@ -44,21 +45,16 @@ namespace Artemis.Core.Services
return (T) DataModelStore.GetAll().FirstOrDefault(d => d.DataModel is T)?.DataModel;
}
public DataModel GetPluginDataModel(PluginImplementation pluginImplementation)
public DataModel? GetPluginDataModel(PluginFeature pluginFeature)
{
return DataModelStore.Get(pluginImplementation.PluginInfo.Guid)?.DataModel;
return DataModelStore.Get(pluginFeature.Id)?.DataModel;
}
public DataModel GetPluginDataModel(Guid pluginGuid)
private void OnPluginFeatureEnabled(object? sender, PluginFeatureEventArgs e)
{
return DataModelStore.Get(pluginGuid)?.DataModel;
}
private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e)
{
if (e.PluginInfo.Plugin is Module module)
if (e.PluginFeature is Module module)
AddModuleDataModel(module);
else if (e.PluginInfo.Plugin is BaseDataModelExpansion dataModelExpansion)
else if (e.PluginFeature is BaseDataModelExpansion dataModelExpansion)
AddDataModelExpansionDataModel(dataModelExpansion);
}
@@ -68,7 +64,7 @@ namespace Artemis.Core.Services
return;
if (module.InternalDataModel.DataModelDescription == null)
throw new ArtemisPluginException(module.PluginInfo, "Module overrides GetDataModelDescription but returned null");
throw new ArtemisPluginFeatureException(module, "Module overrides GetDataModelDescription but returned null");
module.InternalDataModel.IsExpansion = module.InternalExpandsMainDataModel;
RegisterDataModel(module.InternalDataModel);
@@ -77,7 +73,7 @@ namespace Artemis.Core.Services
private void AddDataModelExpansionDataModel(BaseDataModelExpansion dataModelExpansion)
{
if (dataModelExpansion.InternalDataModel.DataModelDescription == null)
throw new ArtemisPluginException(dataModelExpansion.PluginInfo, "Data model expansion overrides GetDataModelDescription but returned null");
throw new ArtemisPluginFeatureException(dataModelExpansion, "Data model expansion overrides GetDataModelDescription but returned null");
dataModelExpansion.InternalDataModel.IsExpansion = true;
RegisterDataModel(dataModelExpansion.InternalDataModel);
@@ -12,9 +12,9 @@ namespace Artemis.Core.Services
/// <summary>
/// Registers a new condition operator for use in layer conditions
/// </summary>
/// <param name="pluginInfo">The PluginInfo of the plugin this condition operator belongs to</param>
/// <param name="plugin">The plugin this condition operator belongs to</param>
/// <param name="conditionOperator">The condition operator to register</param>
ConditionOperatorRegistration RegisterConditionOperator([NotNull] PluginInfo pluginInfo, [NotNull] BaseConditionOperator conditionOperator);
ConditionOperatorRegistration RegisterConditionOperator([NotNull] Plugin plugin, [NotNull] BaseConditionOperator conditionOperator);
/// <summary>
/// Removes a condition operator so it is no longer available for use in layer conditions
@@ -12,9 +12,9 @@ namespace Artemis.Core.Services
/// <summary>
/// Registers a new modifier type for use in data bindings
/// </summary>
/// <param name="pluginInfo">The PluginInfo of the plugin this modifier type belongs to</param>
/// <param name="plugin">The plugin this modifier type belongs to</param>
/// <param name="dataBindingModifierType">The modifier type to register</param>
DataBindingModifierTypeRegistration RegisterModifierType([NotNull] PluginInfo pluginInfo, [NotNull] BaseDataBindingModifierType dataBindingModifierType);
DataBindingModifierTypeRegistration RegisterModifierType([NotNull] Plugin plugin, [NotNull] BaseDataBindingModifierType dataBindingModifierType);
/// <summary>
/// Removes a modifier type so it is no longer available for use in data bindings
@@ -34,13 +34,7 @@ namespace Artemis.Core.Services
/// <summary>
/// If found, returns the data model of the provided plugin
/// </summary>
/// <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
/// </summary>
/// <param name="pluginGuid">The GUID of the plugin to find the data model of</param>
DataModel GetPluginDataModel(Guid pluginGuid);
/// <param name="pluginFeature">The plugin to find the data model of</param>
DataModel? GetPluginDataModel(PluginFeature pluginFeature);
}
}
@@ -38,11 +38,11 @@ namespace Artemis.Core.Services
{
PluginSetting<LayerBrushReference> defaultReference = _settingsService.GetSetting("ProfileEditor.DefaultLayerBrushDescriptor", new LayerBrushReference
{
BrushPluginGuid = Guid.Parse("92a9d6ba-6f7a-4937-94d5-c1d715b4141a"),
LayerBrushProviderId = "Artemis.Plugins.LayerBrushes.Color.ColorBrushProvider-92a9d6ba",
BrushType = "ColorBrush"
});
return LayerBrushStore.Get(defaultReference.Value.BrushPluginGuid, defaultReference.Value.BrushType)?.LayerBrushDescriptor;
return LayerBrushStore.Get(defaultReference.Value.LayerBrushProviderId, defaultReference.Value.BrushType)?.LayerBrushDescriptor;
}
}
}
+1 -1
View File
@@ -9,7 +9,7 @@ namespace Artemis.Core.Services
internal SettingsService(IPluginRepository pluginRepository)
{
_pluginSettings = new PluginSettings(Constants.CorePluginInfo, pluginRepository);
_pluginSettings = new PluginSettings(Constants.CorePlugin, pluginRepository);
}
public PluginSetting<T> GetSetting<T>(string name, T defaultValue = default)
@@ -38,13 +38,13 @@ namespace Artemis.Core.Services
public List<ProfileDescriptor> GetProfileDescriptors(ProfileModule module)
{
List<ProfileEntity> profileEntities = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid);
List<ProfileEntity> profileEntities = _profileRepository.GetByModuleId(module.Id);
return profileEntities.Select(e => new ProfileDescriptor(module, e)).ToList();
}
public ProfileDescriptor CreateProfileDescriptor(ProfileModule module, string name)
{
ProfileEntity profileEntity = new ProfileEntity {Id = Guid.NewGuid(), Name = name, PluginGuid = module.PluginInfo.Guid};
ProfileEntity profileEntity = new ProfileEntity {Id = Guid.NewGuid(), Name = name, ModuleId = module.Id};
_profileRepository.Add(profileEntity);
return new ProfileDescriptor(module, profileEntity);
@@ -258,7 +258,7 @@ namespace Artemis.Core.Services
public ProfileDescriptor GetLastActiveProfile(ProfileModule module)
{
List<ProfileEntity> moduleProfiles = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid);
List<ProfileEntity> moduleProfiles = _profileRepository.GetByModuleId(module.Id);
if (!moduleProfiles.Any())
return CreateProfileDescriptor(module, "Default");
@@ -271,7 +271,7 @@ namespace Artemis.Core.Services
if (module.ActiveProfile == null)
return;
List<ProfileEntity> profileEntities = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid);
List<ProfileEntity> profileEntities = _profileRepository.GetByModuleId(module.Id);
foreach (ProfileEntity profileEntity in profileEntities)
{
profileEntity.IsActive = module.ActiveProfile.EntityId == profileEntity.Id;
@@ -285,7 +285,7 @@ namespace Artemis.Core.Services
/// <param name="surface"></param>
private void ActiveProfilesPopulateLeds(ArtemisSurface surface)
{
List<ProfileModule> profileModules = _pluginManagementService.GetPluginsOfType<ProfileModule>();
List<ProfileModule> profileModules = _pluginManagementService.GetFeaturesOfType<ProfileModule>();
foreach (ProfileModule profileModule in profileModules.Where(p => p.ActiveProfile != null).ToList())
profileModule.ActiveProfile.PopulateLeds(surface);
}
@@ -44,8 +44,8 @@ namespace Artemis.Core.Services
// Add all current devices
foreach (IRGBDevice rgbDevice in _rgbService.LoadedDevices)
{
PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(rgbDevice);
configuration.Devices.Add(new ArtemisDevice(rgbDevice, pluginImplementation, configuration));
PluginFeature pluginFeature = _pluginManagementService.GetDeviceProviderByDevice(rgbDevice);
configuration.Devices.Add(new ArtemisDevice(rgbDevice, pluginFeature, 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)
{
PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(device);
surfaceConfiguration.Devices.Add(new ArtemisDevice(device, pluginImplementation, surfaceConfiguration, position));
PluginFeature pluginFeature = _pluginManagementService.GetDeviceProviderByDevice(device);
surfaceConfiguration.Devices.Add(new ArtemisDevice(device, pluginFeature, surfaceConfiguration, position));
}
}
@@ -178,8 +178,8 @@ namespace Artemis.Core.Services
DeviceEntity existingDeviceConfig = surface.SurfaceEntity.DeviceEntities.FirstOrDefault(d => d.DeviceIdentifier == deviceIdentifier);
if (existingDeviceConfig != null)
{
PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(rgbDevice);
device = new ArtemisDevice(rgbDevice, pluginImplementation, surface, existingDeviceConfig);
PluginFeature pluginFeature = _pluginManagementService.GetDeviceProviderByDevice(rgbDevice);
device = new ArtemisDevice(rgbDevice, pluginFeature, surface, existingDeviceConfig);
}
// Fall back on creating a new device
else
@@ -189,8 +189,8 @@ namespace Artemis.Core.Services
rgbDevice.DeviceInfo,
deviceIdentifier
);
PluginImplementation pluginImplementation = _pluginManagementService.GetPluginByDevice(rgbDevice);
device = new ArtemisDevice(rgbDevice, pluginImplementation, surface);
PluginFeature pluginFeature = _pluginManagementService.GetDeviceProviderByDevice(rgbDevice);
device = new ArtemisDevice(rgbDevice, pluginFeature, surface);
}
surface.Devices.Add(device);