From 931505d135bbc3e19bc05ac0a5f173c4b86b384b Mon Sep 17 00:00:00 2001 From: Kukks Date: Sun, 15 Nov 2020 14:39:21 +0100 Subject: [PATCH] Plugins: Hook System Almost an exact replica of https://developer.wordpress.org/plugins/hooks/ This will allow plugins to extend specific points in business logic, such as validation, invoice payload changes, etc --- .../Contracts/IPluginHookAction.cs | 10 ++++++ .../Contracts/IPluginHookFilter.cs | 11 +++++++ .../Contracts/IPluginHookService.cs | 10 ++++++ .../Contracts/IUIExtension.cs | 9 ++++++ .../Contracts/PluginAction.cs | 15 +++++++++ .../Contracts/PluginHookFilter.cs | 15 +++++++++ .../{IStoreNavExtension.cs => UIExtension.cs} | 7 ----- BTCPayServer/Hosting/BTCPayServerServices.cs | 1 + BTCPayServer/Plugins/PluginService.cs | 31 +++++++++++++++++-- 9 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 BTCPayServer.Abstractions/Contracts/IPluginHookAction.cs create mode 100644 BTCPayServer.Abstractions/Contracts/IPluginHookFilter.cs create mode 100644 BTCPayServer.Abstractions/Contracts/IPluginHookService.cs create mode 100644 BTCPayServer.Abstractions/Contracts/IUIExtension.cs create mode 100644 BTCPayServer.Abstractions/Contracts/PluginAction.cs create mode 100644 BTCPayServer.Abstractions/Contracts/PluginHookFilter.cs rename BTCPayServer.Abstractions/Contracts/{IStoreNavExtension.cs => UIExtension.cs} (72%) diff --git a/BTCPayServer.Abstractions/Contracts/IPluginHookAction.cs b/BTCPayServer.Abstractions/Contracts/IPluginHookAction.cs new file mode 100644 index 000000000..55aa4bdc1 --- /dev/null +++ b/BTCPayServer.Abstractions/Contracts/IPluginHookAction.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace BTCPayServer.Contracts +{ + public interface IPluginHookAction + { + public string Hook { get; } + Task Execute(object args); + } +} \ No newline at end of file diff --git a/BTCPayServer.Abstractions/Contracts/IPluginHookFilter.cs b/BTCPayServer.Abstractions/Contracts/IPluginHookFilter.cs new file mode 100644 index 000000000..54a16f5e6 --- /dev/null +++ b/BTCPayServer.Abstractions/Contracts/IPluginHookFilter.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; + +namespace BTCPayServer.Contracts +{ + public interface IPluginHookFilter + { + public string Hook { get; } + + Task Execute(object args); + } +} \ No newline at end of file diff --git a/BTCPayServer.Abstractions/Contracts/IPluginHookService.cs b/BTCPayServer.Abstractions/Contracts/IPluginHookService.cs new file mode 100644 index 000000000..b1120ad43 --- /dev/null +++ b/BTCPayServer.Abstractions/Contracts/IPluginHookService.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace BTCPayServer.Contracts +{ + public interface IPluginHookService + { + Task ApplyAction(string hook, object args); + Task ApplyFilter(string hook, object args); + } +} \ No newline at end of file diff --git a/BTCPayServer.Abstractions/Contracts/IUIExtension.cs b/BTCPayServer.Abstractions/Contracts/IUIExtension.cs new file mode 100644 index 000000000..b5b2cf5f1 --- /dev/null +++ b/BTCPayServer.Abstractions/Contracts/IUIExtension.cs @@ -0,0 +1,9 @@ +namespace BTCPayServer.Contracts +{ + public interface IUIExtension + { + string Partial { get; } + + string Location { get; } + } +} \ No newline at end of file diff --git a/BTCPayServer.Abstractions/Contracts/PluginAction.cs b/BTCPayServer.Abstractions/Contracts/PluginAction.cs new file mode 100644 index 000000000..9d989f888 --- /dev/null +++ b/BTCPayServer.Abstractions/Contracts/PluginAction.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; + +namespace BTCPayServer.Contracts +{ + public abstract class PluginAction:IPluginHookAction + { + public string Hook { get; } + public Task Execute(object args) + { + return Execute(args is T args1 ? args1 : default); + } + + public abstract Task Execute(T arg); + } +} \ No newline at end of file diff --git a/BTCPayServer.Abstractions/Contracts/PluginHookFilter.cs b/BTCPayServer.Abstractions/Contracts/PluginHookFilter.cs new file mode 100644 index 000000000..24e186ab5 --- /dev/null +++ b/BTCPayServer.Abstractions/Contracts/PluginHookFilter.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; + +namespace BTCPayServer.Contracts +{ + public abstract class PluginHookFilter:IPluginHookFilter + { + public string Hook { get; } + public Task Execute(object args) + { + return Execute(args is T args1 ? args1 : default).ContinueWith(task => task.Result as object); + } + + public abstract Task Execute(T arg); + } +} \ No newline at end of file diff --git a/BTCPayServer.Abstractions/Contracts/IStoreNavExtension.cs b/BTCPayServer.Abstractions/Contracts/UIExtension.cs similarity index 72% rename from BTCPayServer.Abstractions/Contracts/IStoreNavExtension.cs rename to BTCPayServer.Abstractions/Contracts/UIExtension.cs index 4bf60b3c2..62dd41835 100644 --- a/BTCPayServer.Abstractions/Contracts/IStoreNavExtension.cs +++ b/BTCPayServer.Abstractions/Contracts/UIExtension.cs @@ -1,12 +1,5 @@ namespace BTCPayServer.Contracts { - public interface IUIExtension - { - string Partial { get; } - - string Location { get; } - } - public class UIExtension: IUIExtension { public UIExtension(string partial, string location) diff --git a/BTCPayServer/Hosting/BTCPayServerServices.cs b/BTCPayServer/Hosting/BTCPayServerServices.cs index e3d3415ea..9a63d2ae0 100644 --- a/BTCPayServer/Hosting/BTCPayServerServices.cs +++ b/BTCPayServer/Hosting/BTCPayServerServices.cs @@ -149,6 +149,7 @@ namespace BTCPayServer.Hosting services.TryAddSingleton(); services.AddSingleton(); + services.AddSingleton(provider => provider.GetService()); services.TryAddTransient(); services.TryAddSingleton(o => { diff --git a/BTCPayServer/Plugins/PluginService.cs b/BTCPayServer/Plugins/PluginService.cs index 79671887e..84bea57be 100644 --- a/BTCPayServer/Plugins/PluginService.cs +++ b/BTCPayServer/Plugins/PluginService.cs @@ -15,18 +15,21 @@ using Newtonsoft.Json; namespace BTCPayServer.Plugins { - public class PluginService + public class PluginService: IPluginHookService { private readonly BTCPayServerOptions _btcPayServerOptions; private readonly HttpClient _githubClient; - + private readonly IEnumerable _actions; + private readonly IEnumerable _filters; public PluginService(IEnumerable btcPayServerPlugins, - IHttpClientFactory httpClientFactory, BTCPayServerOptions btcPayServerOptions) + IHttpClientFactory httpClientFactory, BTCPayServerOptions btcPayServerOptions,IEnumerable actions, IEnumerable filters) { LoadedPlugins = btcPayServerPlugins; _githubClient = httpClientFactory.CreateClient(); _githubClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("btcpayserver", "1")); _btcPayServerOptions = btcPayServerOptions; + _actions = actions; + _filters = filters; } public IEnumerable LoadedPlugins { get; } @@ -128,5 +131,27 @@ namespace BTCPayServer.Plugins { PluginManager.CancelCommands(_btcPayServerOptions.PluginDir, plugin); } + + public async Task ApplyAction(string hook, object args) + { + var filters = _actions + .Where(filter => filter.Hook.Equals(hook, StringComparison.InvariantCultureIgnoreCase)).ToList(); + foreach (IPluginHookAction pluginHookFilter in filters) + { + await pluginHookFilter.Execute(args); + } + } + + public async Task ApplyFilter(string hook, object args) + { + var filters = _filters + .Where(filter => filter.Hook.Equals(hook, StringComparison.InvariantCultureIgnoreCase)).ToList(); + foreach (IPluginHookFilter pluginHookFilter in filters) + { + args = await pluginHookFilter.Execute(args); + } + + return args; + } } }