1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Plugins UI - Improved error reporting on exceptions during enable

This commit is contained in:
Robert 2021-07-22 23:35:08 +02:00
parent 4e8d0bf70b
commit 66b1620441
6 changed files with 72 additions and 36 deletions

View File

@ -11,7 +11,7 @@ namespace Artemis.Core
public abstract class PluginFeature : CorePropertyChanged, IDisposable public abstract class PluginFeature : CorePropertyChanged, IDisposable
{ {
private bool _isEnabled; private bool _isEnabled;
private Exception? _loadException;
/// <summary> /// <summary>
/// Gets the plugin feature info related to this feature /// Gets the plugin feature info related to this feature
@ -37,15 +37,6 @@ namespace Artemis.Core
internal set => SetAndNotify(ref _isEnabled, value); internal set => SetAndNotify(ref _isEnabled, value);
} }
/// <summary>
/// Gets the exception thrown while loading
/// </summary>
public Exception? LoadException
{
get => _loadException;
internal set => SetAndNotify(ref _loadException, value);
}
/// <summary> /// <summary>
/// Gets the identifier of this plugin feature /// Gets the identifier of this plugin feature
/// </summary> /// </summary>
@ -149,10 +140,10 @@ namespace Artemis.Core
if (isAutoEnable && GetLockFileCreated()) if (isAutoEnable && GetLockFileCreated())
{ {
// Don't wrap existing lock exceptions, simply rethrow them // Don't wrap existing lock exceptions, simply rethrow them
if (LoadException is ArtemisPluginLockException) if (Info.LoadException is ArtemisPluginLockException)
throw LoadException; throw Info.LoadException;
throw new ArtemisPluginLockException(LoadException); throw new ArtemisPluginLockException(Info.LoadException);
} }
CreateLockFile(); CreateLockFile();
@ -165,21 +156,21 @@ namespace Artemis.Core
if (!enableTask.Wait(TimeSpan.FromSeconds(15))) if (!enableTask.Wait(TimeSpan.FromSeconds(15)))
throw new ArtemisPluginException(Plugin, "Plugin load timeout"); throw new ArtemisPluginException(Plugin, "Plugin load timeout");
LoadException = null; Info.LoadException = null;
OnEnabled(); OnEnabled();
} }
// If enable failed, put it back in a disabled state // If enable failed, put it back in a disabled state
catch (Exception e) catch (Exception e)
{ {
IsEnabled = false; IsEnabled = false;
LoadException = e; Info.LoadException = e;
throw; throw;
} }
finally finally
{ {
// Clean up the lock file unless the failure was due to the lock file // Clean up the lock file unless the failure was due to the lock file
// After all, we failed but not miserably :) // After all, we failed but not miserably :)
if (!(LoadException is ArtemisPluginLockException)) if (Info.LoadException is not ArtemisPluginLockException)
DeleteLockFile(); DeleteLockFile();
} }
} }

View File

@ -17,6 +17,7 @@ namespace Artemis.Core
[JsonObject(MemberSerialization.OptIn)] [JsonObject(MemberSerialization.OptIn)]
public class PluginFeatureInfo : CorePropertyChanged, IPrerequisitesSubject public class PluginFeatureInfo : CorePropertyChanged, IPrerequisitesSubject
{ {
private Exception? _loadException;
private string? _description; private string? _description;
private string? _icon; private string? _icon;
private PluginFeature? _instance; private PluginFeature? _instance;
@ -80,6 +81,15 @@ namespace Artemis.Core
/// </summary> /// </summary>
public Type FeatureType { get; } public Type FeatureType { get; }
/// <summary>
/// Gets the exception thrown while loading
/// </summary>
public Exception? LoadException
{
get => _loadException;
internal set => SetAndNotify(ref _loadException, value);
}
/// <summary> /// <summary>
/// The name of the plugin /// The name of the plugin
/// </summary> /// </summary>

View File

@ -426,6 +426,7 @@ namespace Artemis.Core.Services
catch (Exception e) catch (Exception e)
{ {
_logger.Warning(new ArtemisPluginException(plugin, "Failed to instantiate feature", e), "Failed to instantiate feature", plugin); _logger.Warning(new ArtemisPluginException(plugin, "Failed to instantiate feature", e), "Failed to instantiate feature", plugin);
featureInfo.LoadException = e;
} }
} }
@ -613,6 +614,9 @@ namespace Artemis.Core.Services
new ArtemisPluginException(pluginFeature.Plugin, $"Exception during SetEnabled(true) on {pluginFeature}", e), new ArtemisPluginException(pluginFeature.Plugin, $"Exception during SetEnabled(true) on {pluginFeature}", e),
"Failed to enable plugin" "Failed to enable plugin"
); );
if (!isAutoEnable)
throw;
} }
finally finally
{ {

View File

@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Settings" xmlns:local="clr-namespace:Artemis.UI.Screens.Settings"
xmlns:s="https://github.com/canton7/Stylet" xmlns:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:SettingsTabsViewModel}"> d:DataContext="{d:DesignInstance local:SettingsTabsViewModel}">
@ -16,18 +17,31 @@
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>
<TabControl Style="{StaticResource MaterialDesignAppBarTabControl}" <Grid>
ItemsSource="{Binding Items}" <TabControl Style="{StaticResource MaterialDesignAppBarTabControl}"
SelectedItem="{Binding ActiveItem}" ItemsSource="{Binding Items}"
DisplayMemberPath="DisplayName"> SelectedItem="{Binding ActiveItem}"
<TabControl.ContentTemplate> DisplayMemberPath="DisplayName">
<DataTemplate> <TabControl.ContentTemplate>
<ContentControl s:View.Model="{Binding IsAsync=True}" <DataTemplate>
VerticalContentAlignment="Stretch" <ContentControl s:View.Model="{Binding IsAsync=True}"
HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"
IsTabStop="False" HorizontalContentAlignment="Stretch"
TextElement.Foreground="{DynamicResource MaterialDesignBody}" /> IsTabStop="False"
</DataTemplate> TextElement.Foreground="{DynamicResource MaterialDesignBody}" />
</TabControl.ContentTemplate> </DataTemplate>
</TabControl> </TabControl.ContentTemplate>
</TabControl>
<!-- Bug: materialDesign:RippleAssist.RippleOnTop doesn't look as nice but otherwise it doesn't work at all, not sure why -->
<Button Style="{StaticResource MaterialDesignIconForegroundButton}"
VerticalAlignment="Top"
HorizontalAlignment="Right"
ToolTip="Open debugger"
Command="{s:Action ShowDebugger}"
materialDesign:RippleAssist.RippleOnTop="True">
<materialDesign:PackIcon Kind="Matrix" />
</Button>
</Grid>
</UserControl> </UserControl>

View File

@ -2,18 +2,23 @@
using Artemis.UI.Screens.Settings.Tabs.Devices; using Artemis.UI.Screens.Settings.Tabs.Devices;
using Artemis.UI.Screens.Settings.Tabs.General; using Artemis.UI.Screens.Settings.Tabs.General;
using Artemis.UI.Screens.Settings.Tabs.Plugins; using Artemis.UI.Screens.Settings.Tabs.Plugins;
using Artemis.UI.Services;
using Stylet; using Stylet;
namespace Artemis.UI.Screens.Settings namespace Artemis.UI.Screens.Settings
{ {
public class SettingsTabsViewModel : Conductor<Screen>.Collection.OneActive public class SettingsTabsViewModel : Conductor<Screen>.Collection.OneActive
{ {
private readonly IDebugService _debugService;
public SettingsTabsViewModel( public SettingsTabsViewModel(
GeneralSettingsTabViewModel generalSettingsTabViewModel, GeneralSettingsTabViewModel generalSettingsTabViewModel,
PluginSettingsTabViewModel pluginSettingsTabViewModel, PluginSettingsTabViewModel pluginSettingsTabViewModel,
DeviceSettingsTabViewModel deviceSettingsTabViewModel, DeviceSettingsTabViewModel deviceSettingsTabViewModel,
AboutTabViewModel aboutTabViewModel) AboutTabViewModel aboutTabViewModel,
IDebugService debugService)
{ {
_debugService = debugService;
DisplayName = "Settings"; DisplayName = "Settings";
Items.Add(generalSettingsTabViewModel); Items.Add(generalSettingsTabViewModel);
@ -23,5 +28,10 @@ namespace Artemis.UI.Screens.Settings
ActiveItem = generalSettingsTabViewModel; ActiveItem = generalSettingsTabViewModel;
} }
public void ShowDebugger()
{
_debugService.ShowDebugger();
}
} }
} }

View File

@ -37,7 +37,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
} }
public PluginFeatureInfo FeatureInfo { get; } public PluginFeatureInfo FeatureInfo { get; }
public Exception LoadException => FeatureInfo.Instance?.LoadException; public Exception LoadException => FeatureInfo.LoadException;
public bool ShowShield { get; } public bool ShowShield { get; }
@ -81,7 +81,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
public async Task InstallPrerequisites() public async Task InstallPrerequisites()
{ {
if (FeatureInfo.Prerequisites.Any()) if (FeatureInfo.Prerequisites.Any())
await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List<IPrerequisitesSubject> { FeatureInfo }); await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List<IPrerequisitesSubject> {FeatureInfo});
} }
public async Task RemovePrerequisites() public async Task RemovePrerequisites()
@ -119,12 +119,19 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
private async Task UpdateEnabled(bool enable) private async Task UpdateEnabled(bool enable)
{ {
if (IsEnabled == enable || FeatureInfo.Instance == null) if (IsEnabled == enable)
{ {
NotifyOfPropertyChange(nameof(IsEnabled)); NotifyOfPropertyChange(nameof(IsEnabled));
return; return;
} }
if (FeatureInfo.Instance == null)
{
NotifyOfPropertyChange(nameof(IsEnabled));
_messageService.ShowMessage($"Feature '{FeatureInfo.Name}' is in a broken state and cannot enable.", "VIEW LOGS", ShowLogsFolder);
return;
}
if (enable) if (enable)
{ {
Enabling = true; Enabling = true;
@ -144,7 +151,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
// Check if all prerequisites are met async // Check if all prerequisites are met async
if (!FeatureInfo.ArePrerequisitesMet()) if (!FeatureInfo.ArePrerequisitesMet())
{ {
await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List<IPrerequisitesSubject> { FeatureInfo }); await PluginPrerequisitesInstallDialogViewModel.Show(_dialogService, new List<IPrerequisitesSubject> {FeatureInfo});
if (!FeatureInfo.ArePrerequisitesMet()) if (!FeatureInfo.ArePrerequisitesMet())
{ {
NotifyOfPropertyChange(nameof(IsEnabled)); NotifyOfPropertyChange(nameof(IsEnabled));
@ -156,7 +163,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
} }
catch (Exception e) catch (Exception e)
{ {
_messageService.ShowMessage($"Failed to enable {FeatureInfo.Name}\r\n{e.Message}", "VIEW LOGS", ShowLogsFolder); _messageService.ShowMessage($"Failed to enable '{FeatureInfo.Name}'.\r\n{e.Message}", "VIEW LOGS", ShowLogsFolder);
} }
finally finally
{ {