Do not call interface methods for init failed plugins

This commit is contained in:
Jack251970 2025-07-21 17:33:47 +08:00
parent d4a1953747
commit 324b3eb081
2 changed files with 27 additions and 15 deletions

View file

@ -59,7 +59,7 @@ namespace Flow.Launcher.Core.Plugin
/// </summary>
public static void Save()
{
foreach (var pluginPair in GetAllInitializedPlugins())
foreach (var pluginPair in GetAllInitializedPlugins(false))
{
var savable = pluginPair.Plugin as ISavable;
try
@ -78,7 +78,8 @@ namespace Flow.Launcher.Core.Plugin
public static async ValueTask DisposePluginsAsync()
{
foreach (var pluginPair in GetAllInitializedPlugins())
// Still call dispose for all plugins even if initialization failed, so that we can clean up resources
foreach (var pluginPair in GetAllInitializedPlugins(true))
{
await DisposePluginAsync(pluginPair);
}
@ -106,7 +107,7 @@ namespace Flow.Launcher.Core.Plugin
public static async Task ReloadDataAsync()
{
await Task.WhenAll([.. GetAllInitializedPlugins().Select(plugin => plugin.Plugin switch
await Task.WhenAll([.. GetAllInitializedPlugins(false).Select(plugin => plugin.Plugin switch
{
IReloadable p => Task.Run(p.ReloadData),
IAsyncReloadable p => p.ReloadDataAsync(),
@ -120,7 +121,7 @@ namespace Flow.Launcher.Core.Plugin
public static async Task OpenExternalPreviewAsync(string path, bool sendFailToast = true)
{
await Task.WhenAll([.. GetAllInitializedPlugins().Select(plugin => plugin.Plugin switch
await Task.WhenAll([.. GetAllInitializedPlugins(false).Select(plugin => plugin.Plugin switch
{
IAsyncExternalPreview p => p.OpenPreviewAsync(path, sendFailToast),
_ => Task.CompletedTask,
@ -129,7 +130,7 @@ namespace Flow.Launcher.Core.Plugin
public static async Task CloseExternalPreviewAsync()
{
await Task.WhenAll([.. GetAllInitializedPlugins().Select(plugin => plugin.Plugin switch
await Task.WhenAll([.. GetAllInitializedPlugins(false).Select(plugin => plugin.Plugin switch
{
IAsyncExternalPreview p => p.ClosePreviewAsync(),
_ => Task.CompletedTask,
@ -138,7 +139,7 @@ namespace Flow.Launcher.Core.Plugin
public static async Task SwitchExternalPreviewAsync(string path, bool sendFailToast = true)
{
await Task.WhenAll([.. GetAllInitializedPlugins().Select(plugin => plugin.Plugin switch
await Task.WhenAll([.. GetAllInitializedPlugins(false).Select(plugin => plugin.Plugin switch
{
IAsyncExternalPreview p => p.SwitchPreviewAsync(path, sendFailToast),
_ => Task.CompletedTask,
@ -523,9 +524,17 @@ namespace Flow.Launcher.Core.Plugin
return [.. _allLoadedPlugins];
}
public static List<PluginPair> GetAllInitializedPlugins()
public static List<PluginPair> GetAllInitializedPlugins(bool containFailed)
{
return [.. _allInitializedPlugins.Values];
if (containFailed)
{
return [.. _allInitializedPlugins.Values];
}
else
{
return [.. _allInitializedPlugins.Values
.Where(p => !_initFailedPlugins.ContainsKey(p.Metadata.ID))];
}
}
public static List<PluginPair> GetGlobalPlugins()
@ -695,9 +704,10 @@ namespace Flow.Launcher.Core.Plugin
if (!Version.TryParse(newMetadata.Version, out var newVersion))
return true; // If version is not valid, we assume it is lesser than any existing version
return GetAllInitializedPlugins().Any(x => x.Metadata.ID == newMetadata.ID
&& Version.TryParse(x.Metadata.Version, out var version)
&& newVersion <= version);
// Get all plugins even if initialization failed so that we can check if the plugin with the same ID exists
return GetAllInitializedPlugins(true).Any(x => x.Metadata.ID == newMetadata.ID
&& Version.TryParse(x.Metadata.Version, out var version)
&& newVersion <= version);
}
#endregion
@ -839,7 +849,7 @@ namespace Flow.Launcher.Core.Plugin
// If we want to remove plugin from AllPlugins,
// we need to dispose them so that they can release file handles
// which can help FL to delete the plugin settings & cache folders successfully
var pluginPairs = GetAllInitializedPlugins().Where(p => p.Metadata.ID == plugin.ID).ToList();
var pluginPairs = GetAllInitializedPlugins(true).Where(p => p.Metadata.ID == plugin.ID).ToList();
foreach (var pluginPair in pluginPairs)
{
await DisposePluginAsync(pluginPair);
@ -885,11 +895,12 @@ namespace Flow.Launcher.Core.Plugin
}
Settings.RemovePluginSettings(plugin.ID);
_allInitializedPlugins.TryRemove(plugin.ID, out var item);
_globalPlugins.TryRemove(plugin.ID, out var item1);
_initFailedPlugins.TryRemove(plugin.ID, out var item1);
_globalPlugins.TryRemove(plugin.ID, out var item2);
var keysToRemove = _nonGlobalPlugins.Where(p => p.Value.Metadata.ID == plugin.ID).Select(p => p.Key).ToList();
foreach (var key in keysToRemove)
{
_nonGlobalPlugins.Remove(key, out var item2);
_nonGlobalPlugins.Remove(key, out var item3);
}
}

View file

@ -116,7 +116,8 @@ public partial class SettingsPanePluginsViewModel : BaseModel
private List<PluginViewModel>? _pluginViewModels;
// Get all initialized plugins and ignore those that are not initialized
public List<PluginViewModel> PluginViewModels => _pluginViewModels ??= PluginManager.GetAllInitializedPlugins()
// Include those init failed plugins so that we can uninstall them
public List<PluginViewModel> PluginViewModels => _pluginViewModels ??= PluginManager.GetAllInitializedPlugins(true)
.OrderBy(plugin => plugin.Metadata.Disabled)
.ThenBy(plugin => plugin.Metadata.Name)
.Select(plugin => new PluginViewModel