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
This commit is contained in:
Kukks 2020-11-15 14:39:21 +01:00
parent 6c7433b2f1
commit 931505d135
9 changed files with 99 additions and 10 deletions

View File

@ -0,0 +1,10 @@
using System.Threading.Tasks;
namespace BTCPayServer.Contracts
{
public interface IPluginHookAction
{
public string Hook { get; }
Task Execute(object args);
}
}

View File

@ -0,0 +1,11 @@
using System.Threading.Tasks;
namespace BTCPayServer.Contracts
{
public interface IPluginHookFilter
{
public string Hook { get; }
Task<object> Execute(object args);
}
}

View File

@ -0,0 +1,10 @@
using System.Threading.Tasks;
namespace BTCPayServer.Contracts
{
public interface IPluginHookService
{
Task ApplyAction(string hook, object args);
Task<object> ApplyFilter(string hook, object args);
}
}

View File

@ -0,0 +1,9 @@
namespace BTCPayServer.Contracts
{
public interface IUIExtension
{
string Partial { get; }
string Location { get; }
}
}

View File

@ -0,0 +1,15 @@
using System.Threading.Tasks;
namespace BTCPayServer.Contracts
{
public abstract class PluginAction<T>:IPluginHookAction
{
public string Hook { get; }
public Task Execute(object args)
{
return Execute(args is T args1 ? args1 : default);
}
public abstract Task Execute(T arg);
}
}

View File

@ -0,0 +1,15 @@
using System.Threading.Tasks;
namespace BTCPayServer.Contracts
{
public abstract class PluginHookFilter<T>:IPluginHookFilter
{
public string Hook { get; }
public Task<object> Execute(object args)
{
return Execute(args is T args1 ? args1 : default).ContinueWith(task => task.Result as object);
}
public abstract Task<T> Execute(T arg);
}
}

View File

@ -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)

View File

@ -149,6 +149,7 @@ namespace BTCPayServer.Hosting
services.TryAddSingleton<AppService>();
services.AddSingleton<PluginService>();
services.AddSingleton<IPluginHookService>(provider => provider.GetService<PluginService>());
services.TryAddTransient<Safe>();
services.TryAddSingleton<Ganss.XSS.HtmlSanitizer>(o =>
{

View File

@ -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<IPluginHookAction> _actions;
private readonly IEnumerable<IPluginHookFilter> _filters;
public PluginService(IEnumerable<IBTCPayServerPlugin> btcPayServerPlugins,
IHttpClientFactory httpClientFactory, BTCPayServerOptions btcPayServerOptions)
IHttpClientFactory httpClientFactory, BTCPayServerOptions btcPayServerOptions,IEnumerable<IPluginHookAction> actions, IEnumerable<IPluginHookFilter> filters)
{
LoadedPlugins = btcPayServerPlugins;
_githubClient = httpClientFactory.CreateClient();
_githubClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("btcpayserver", "1"));
_btcPayServerOptions = btcPayServerOptions;
_actions = actions;
_filters = filters;
}
public IEnumerable<IBTCPayServerPlugin> 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<object> 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;
}
}
}