Add support for async plugins

This commit is contained in:
Stone_Red
2025-12-25 01:23:03 +01:00
parent 43c77e6a36
commit 9e9c49214a
4 changed files with 49 additions and 5 deletions
@@ -11,7 +11,7 @@ using System.Threading.Tasks;
namespace DesktopMagic.BuiltInPlugins; namespace DesktopMagic.BuiltInPlugins;
public class WeatherPlugin : Plugin public class WeatherPlugin : AsyncPlugin
{ {
[Setting("city-name", "City Name")] [Setting("city-name", "City Name")]
private readonly TextBox cityInput = new TextBox("Berlin"); private readonly TextBox cityInput = new TextBox("Berlin");
@@ -74,12 +74,12 @@ public class WeatherPlugin : Plugin
}; };
} }
public override Bitmap Main() public override async Task<Bitmap?> MainAsync()
{ {
// Periodic background update // Periodic background update
if (!isLoading && cachedLat != null && cachedLon != null) if (!isLoading && cachedLat != null && cachedLon != null)
{ {
_ = UpdateWeatherOnly(cachedLat, cachedLon); await UpdateWeatherOnly(cachedLat, cachedLon);
} }
Bitmap bmp = new Bitmap(1200, 800); Bitmap bmp = new Bitmap(1200, 800);
+1
View File
@@ -12,3 +12,4 @@ using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Major Code Smell", "S3885:\"Assembly.Load\" should be used", Justification = "Assembly.Load does not load dependencies", Scope = "member", Target = "~M:DesktopMagic.PluginWindow.ExecuteSource")] [assembly: SuppressMessage("Major Code Smell", "S3885:\"Assembly.Load\" should be used", Justification = "Assembly.Load does not load dependencies", Scope = "member", Target = "~M:DesktopMagic.PluginWindow.ExecuteSource")]
[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "<Pending>", Scope = "member", Target = "~M:DesktopMagic.MainWindow.OpenPluginsFolderButton_Click(System.Object,System.Windows.RoutedEventArgs)")] [assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "<Pending>", Scope = "member", Target = "~M:DesktopMagic.MainWindow.OpenPluginsFolderButton_Click(System.Object,System.Windows.RoutedEventArgs)")]
[assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "<Pending>", Scope = "member", Target = "~M:DesktopMagic.MainWindow.ScrollViewer_PreviewMouseWheel(System.Object,System.Windows.Input.MouseWheelEventArgs)")] [assembly: SuppressMessage("Minor Code Smell", "S2325:Methods and properties that don't access instance data should be static", Justification = "<Pending>", Scope = "member", Target = "~M:DesktopMagic.MainWindow.ScrollViewer_PreviewMouseWheel(System.Object,System.Windows.Input.MouseWheelEventArgs)")]
[assembly: SuppressMessage("Major Code Smell", "S6966:Awaitable method should be used", Justification = "Breaks stuff", Scope = "member", Target = "~M:DesktopMagic.PluginWindow.UpdateTimer_Elapsed(System.Object,System.Timers.ElapsedEventArgs)")]
+11 -2
View File
@@ -401,13 +401,22 @@ public partial class PluginWindow : Window, IPluginWindow
} }
} }
private void UpdateTimer_Elapsed(object? sender, ElapsedEventArgs? e) private async void UpdateTimer_Elapsed(object? sender, ElapsedEventArgs? e)
{ {
try try
{ {
if (IsRunning && pluginClassInstance is not null) if (IsRunning && pluginClassInstance is not null)
{ {
Bitmap? result = pluginClassInstance.Main(); Bitmap? result;
if (pluginClassInstance is AsyncPlugin asyncPlugin)
{
result = await asyncPlugin.MainAsync();
}
else
{
result = pluginClassInstance.Main();
}
if (pluginClassInstance.UpdateInterval > 0) if (pluginClassInstance.UpdateInterval > 0)
{ {
+34
View File
@@ -0,0 +1,34 @@
using System;
using System.Drawing;
using System.Threading.Tasks;
namespace DesktopMagic.Api;
/// <summary>
/// Provides an abstract base class for plugins that execute asynchronously. Derive from this class to implement plugins
/// whose main logic runs in a non-blocking manner using asynchronous operations.
/// </summary>
/// <remarks>AsyncPlugin is intended for scenarios where plugin execution should not block the calling thread.
/// Override the MainAsync method to implement asynchronous plugin behavior. The synchronous Main method is sealed and
/// obsolete; it cannot be used for execution and will always throw an exception. Use MainAsync for all plugin logic.
/// The MainAsync method is typically invoked when the UpdateInterval elapses, allowing periodic asynchronous
/// execution.</remarks>
public abstract class AsyncPlugin : Plugin
{
/// <summary>
/// Occurs when the <see cref="Plugin.UpdateInterval"/> elapses.
/// </summary>
/// <returns></returns>
public abstract Task<Bitmap?> MainAsync();
/// <summary>
/// This method should not be called directly! Override and use <see cref="MainAsync"/> for asynchronous plugin operations.
/// </summary>
/// <remarks>This method only exists to fulfill base class requirements.</remarks>
/// <returns>Calling it will always result in an <see cref="InvalidOperationException"/>.</returns>
/// <exception cref="InvalidOperationException">Thrown if this method is called directly. Use MainAsync for plugin execution instead.</exception>
public sealed override Bitmap? Main()
{
throw new InvalidOperationException($"AsyncPlugin.Main() should not be called directly. Override {nameof(MainAsync)} instead.");
}
}