From 58e07ae5bd50f174cd6689d396156c951bd78528 Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Mon, 29 Jun 2020 23:24:49 +0200 Subject: [PATCH] Plugins - Added timeout for plugin enable Plugins - Delete lock file even on exception, only leave it in place on crash Plugins - Added --ignore-plugin-lock startup argument UI - Renamed -autorun argument to --autorun --- src/Artemis.Core/Plugins/Abstract/Plugin.cs | 22 ++++++++++++++----- src/Artemis.Core/Services/CoreService.cs | 3 ++- .../Services/Interfaces/ICoreService.cs | 6 +++++ .../Services/Interfaces/IPluginService.cs | 2 +- src/Artemis.Core/Services/PluginService.cs | 21 ++++++------------ src/Artemis.UI/Bootstrapper.cs | 3 ++- .../DataModelListViewModel.cs | 3 +-- .../Screens/Settings/SettingsViewModel.cs | 2 +- src/Artemis.UI/Screens/TrayViewModel.cs | 2 +- .../CorsairDeviceProvider.cs | 17 ++++++++++++++ .../GeneralModule.cs | 2 ++ 11 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/Artemis.Core/Plugins/Abstract/Plugin.cs b/src/Artemis.Core/Plugins/Abstract/Plugin.cs index 71197abfb..e96463090 100644 --- a/src/Artemis.Core/Plugins/Abstract/Plugin.cs +++ b/src/Artemis.Core/Plugins/Abstract/Plugin.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using Artemis.Core.Plugins.Abstract.ViewModels; using Artemis.Core.Plugins.Exceptions; using Artemis.Core.Plugins.Models; @@ -11,7 +12,7 @@ namespace Artemis.Core.Plugins.Abstract /// public abstract class Plugin : IDisposable { - public PluginInfo PluginInfo { get; internal set; } + public PluginInfo PluginInfo { get; internal set; } /// /// Gets whether the plugin is enabled @@ -60,7 +61,7 @@ namespace Artemis.Core.Plugins.Abstract // Don't wrap existing lock exceptions, simply rethrow them if (PluginInfo.LoadException is ArtemisPluginLockException) throw PluginInfo.LoadException; - + throw new ArtemisPluginLockException(PluginInfo.LoadException); } @@ -68,9 +69,15 @@ namespace Artemis.Core.Plugins.Abstract PluginInfo.Enabled = true; PluginInfo.CreateLockFile(); - InternalEnablePlugin(); - OnPluginEnabled(); + // 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) @@ -80,8 +87,11 @@ namespace Artemis.Core.Plugins.Abstract PluginInfo.LoadException = e; throw; } - - PluginInfo.DeleteLockFile(); + finally + { + if (!(PluginInfo.LoadException is ArtemisPluginLockException)) + PluginInfo.DeleteLockFile(); + } } else if (!enable && Enabled) { diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index 899a49c42..bc99e057a 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -63,6 +63,7 @@ namespace Artemis.Core.Services public TimeSpan FrameTime { get; private set; } public bool PluginUpdatingDisabled { get; set; } public bool ModuleRenderingDisabled { get; set; } + public List StartupArguments { get; set; } public void Dispose() { @@ -83,7 +84,7 @@ namespace Artemis.Core.Services // Initialize the services _pluginService.CopyBuiltInPlugins(); - _pluginService.LoadPlugins(); + _pluginService.LoadPlugins(StartupArguments.Contains("--ignore-plugin-lock")); var surfaceConfig = _surfaceService.ActiveSurface; if (surfaceConfig != null) diff --git a/src/Artemis.Core/Services/Interfaces/ICoreService.cs b/src/Artemis.Core/Services/Interfaces/ICoreService.cs index 3cf78c7cd..2f2283f35 100644 --- a/src/Artemis.Core/Services/Interfaces/ICoreService.cs +++ b/src/Artemis.Core/Services/Interfaces/ICoreService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Artemis.Core.Events; namespace Artemis.Core.Services.Interfaces @@ -25,6 +26,11 @@ namespace Artemis.Core.Services.Interfaces /// bool ModuleRenderingDisabled { get; set; } + /// + /// Gets or sets a list of startup arguments + /// + List StartupArguments { get; set; } + /// /// Initializes the core, only call once /// diff --git a/src/Artemis.Core/Services/Interfaces/IPluginService.cs b/src/Artemis.Core/Services/Interfaces/IPluginService.cs index 25ac1e82a..ce2915738 100644 --- a/src/Artemis.Core/Services/Interfaces/IPluginService.cs +++ b/src/Artemis.Core/Services/Interfaces/IPluginService.cs @@ -23,7 +23,7 @@ namespace Artemis.Core.Services.Interfaces /// /// Loads all installed plugins. If plugins already loaded this will reload them all /// - void LoadPlugins(); + void LoadPlugins(bool ignorePluginLock); /// /// Unloads all installed plugins. diff --git a/src/Artemis.Core/Services/PluginService.cs b/src/Artemis.Core/Services/PluginService.cs index 75cac73b3..db09b13f2 100644 --- a/src/Artemis.Core/Services/PluginService.cs +++ b/src/Artemis.Core/Services/PluginService.cs @@ -107,8 +107,7 @@ namespace Artemis.Core.Services } } - /// - public void LoadPlugins() + public void LoadPlugins(bool ignorePluginLock) { if (LoadingPlugins) throw new ArtemisCoreException("Cannot load plugins while a previous load hasn't been completed yet."); @@ -150,7 +149,7 @@ namespace Artemis.Core.Services { try { - EnablePlugin(pluginInfo.Instance, true); + EnablePlugin(pluginInfo.Instance, !ignorePluginLock); } catch (Exception) { @@ -305,13 +304,13 @@ 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) + if (isAutoEnable) plugin.PluginInfo.Enabled = true; plugin.PluginInfo.ApplyToEntity(); _pluginRepository.SavePlugin(plugin.PluginInfo.PluginEntity); - if (plugin.PluginInfo.Enabled) + if (plugin.PluginInfo.Enabled) _logger.Debug("Successfully enabled plugin {pluginInfo}", plugin.PluginInfo); } } @@ -351,10 +350,7 @@ namespace Artemis.Core.Services /// public PluginInfo GetPluginInfo(Plugin plugin) { - lock (_plugins) - { - return _plugins.FirstOrDefault(p => p.Instance == plugin); - } + return _plugins.FirstOrDefault(p => p.Instance == plugin); } /// @@ -366,10 +362,7 @@ namespace Artemis.Core.Services /// public List GetPluginsOfType() where T : Plugin { - lock (_plugins) - { - return _plugins.Where(p => p.Enabled && p.Instance is T).Select(p => (T) p.Instance).ToList(); - } + return _plugins.Where(p => p.Enabled && p.Instance is T).Select(p => (T) p.Instance).ToList(); } public Plugin GetDevicePlugin(IRGBDevice rgbDevice) @@ -393,7 +386,7 @@ namespace Artemis.Core.Services Directory.CreateDirectory(pluginDirectory.FullName); builtInPluginDirectory.CopyFilesRecursively(pluginDirectory); - if (createLockFile) + if (createLockFile) File.Create(Path.Combine(pluginDirectory.FullName, "artemis.lock")).Close(); } diff --git a/src/Artemis.UI/Bootstrapper.cs b/src/Artemis.UI/Bootstrapper.cs index c24342daa..0473f8167 100644 --- a/src/Artemis.UI/Bootstrapper.cs +++ b/src/Artemis.UI/Bootstrapper.cs @@ -60,12 +60,13 @@ namespace Artemis.UI { try { - if (StartupArguments.Contains("-autorun")) + if (StartupArguments.Contains("--autorun")) { logger.Information("Sleeping for 15 seconds on auto run to allow applications like iCUE and LGS to start"); await Task.Delay(TimeSpan.FromSeconds(15)); } + _core.StartupArguments = StartupArguments; _core.Initialize(); } catch (Exception e) diff --git a/src/Artemis.UI/DataModelVisualization/DataModelListViewModel.cs b/src/Artemis.UI/DataModelVisualization/DataModelListViewModel.cs index 4c6ad5910..dc121c50e 100644 --- a/src/Artemis.UI/DataModelVisualization/DataModelListViewModel.cs +++ b/src/Artemis.UI/DataModelVisualization/DataModelListViewModel.cs @@ -33,14 +33,13 @@ namespace Artemis.UI.DataModelVisualization foreach (var item in List) { DataModelVisualizationViewModel child; - if (Children.Count < index ) + if (Children.Count < index) { child = CreateChild(item); Children.Add(child); } else { - // TODO: This wont fly when mixing DataModels and DataModelProperties child = Children[index]; child.Model = item; } diff --git a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs index 04509b556..0535fe682 100644 --- a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs @@ -211,7 +211,7 @@ namespace Artemis.UI.Screens.Settings if (File.Exists(autoRunFile)) File.Delete(autoRunFile); if (StartWithWindows) - ShortcutUtilities.Create(autoRunFile, executableFile, "-autorun", new FileInfo(executableFile).DirectoryName, "Artemis", "", ""); + ShortcutUtilities.Create(autoRunFile, executableFile, "--autorun", new FileInfo(executableFile).DirectoryName, "Artemis", "", ""); } catch (Exception e) { diff --git a/src/Artemis.UI/Screens/TrayViewModel.cs b/src/Artemis.UI/Screens/TrayViewModel.cs index 6000de372..cfd4bcb00 100644 --- a/src/Artemis.UI/Screens/TrayViewModel.cs +++ b/src/Artemis.UI/Screens/TrayViewModel.cs @@ -25,7 +25,7 @@ namespace Artemis.UI.Screens _eventAggregator = eventAggregator; CanShowRootViewModel = true; - var autoRunning = Bootstrapper.StartupArguments.Contains("-autorun"); + var autoRunning = Bootstrapper.StartupArguments.Contains("--autorun"); var showOnAutoRun = settingsService.GetSetting("UI.ShowOnStartup", true).Value; if (!autoRunning || showOnAutoRun) { diff --git a/src/Plugins/Artemis.Plugins.Devices.Corsair/CorsairDeviceProvider.cs b/src/Plugins/Artemis.Plugins.Devices.Corsair/CorsairDeviceProvider.cs index 4ba23b7f5..2b46d0c81 100644 --- a/src/Plugins/Artemis.Plugins.Devices.Corsair/CorsairDeviceProvider.cs +++ b/src/Plugins/Artemis.Plugins.Devices.Corsair/CorsairDeviceProvider.cs @@ -1,6 +1,8 @@ using System.IO; +using System.Threading.Tasks; using Artemis.Core.Plugins.Abstract; using Artemis.Core.Services.Interfaces; +using Microsoft.Win32; using RGB.NET.Core; using RGB.NET.Devices.Corsair; @@ -22,6 +24,21 @@ namespace Artemis.Plugins.Devices.Corsair RGB.NET.Devices.Corsair.CorsairDeviceProvider.PossibleX64NativePaths.Add(Path.Combine(PluginInfo.Directory.FullName, "x64", "CUESDK.x64_2017.dll")); RGB.NET.Devices.Corsair.CorsairDeviceProvider.PossibleX86NativePaths.Add(Path.Combine(PluginInfo.Directory.FullName, "x86", "CUESDK_2017.dll")); _rgbService.AddDeviceProvider(RgbDeviceProvider); + + SystemEvents.PowerModeChanged += SystemEventsOnPowerModeChanged; + } + + private void SystemEventsOnPowerModeChanged(object sender, PowerModeChangedEventArgs e) + { + // This may be required for some device providers + // if (e.Mode == PowerModes.Resume) + // { + // Task.Run(async () => + // { + // await Task.Delay(5000); + // RGB.NET.Devices.Corsair.CorsairDeviceProvider.Instance.Initialize(); + // }); + // } } } } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs b/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs index f7bebfc53..e029fb6d3 100644 --- a/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs +++ b/src/Plugins/Artemis.Plugins.Modules.General/GeneralModule.cs @@ -31,6 +31,8 @@ namespace Artemis.Plugins.Modules.General DataModel.IntsList[0] = _rand.Next(); DataModel.IntsList[2] = _rand.Next(); + + base.Update(deltaTime); } public override void EnablePlugin()