diff options
Diffstat (limited to 'lib/VNLib.Plugins.Extensions.Loading/src')
6 files changed, 94 insertions, 20 deletions
diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/Events/EventManagment.cs b/lib/VNLib.Plugins.Extensions.Loading/src/Events/EventManagment.cs index fde67f7..bde6986 100644 --- a/lib/VNLib.Plugins.Extensions.Loading/src/Events/EventManagment.cs +++ b/lib/VNLib.Plugins.Extensions.Loading/src/Events/EventManagment.cs @@ -60,7 +60,7 @@ namespace VNLib.Plugins.Extensions.Loading.Events plugin.Log.Verbose("Interval for {t} scheduled", interval); //Run interval on plugins bg scheduler - _ = plugin.DeferTask(() => RunIntervalOnPluginScheduler(plugin, asyncCallback, interval, immediate)); + _ = plugin.ObserveTask(() => RunIntervalOnPluginScheduler(plugin, asyncCallback, interval, immediate)); } private static async Task RunIntervalOnPluginScheduler(PluginBase plugin, AsyncSchedulableCallback callback, TimeSpan interval, bool immediate) diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/IAsyncBackgroundWork.cs b/lib/VNLib.Plugins.Extensions.Loading/src/IAsyncBackgroundWork.cs new file mode 100644 index 0000000..9fb66a2 --- /dev/null +++ b/lib/VNLib.Plugins.Extensions.Loading/src/IAsyncBackgroundWork.cs @@ -0,0 +1,46 @@ +/* +* Copyright (c) 2022 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Plugins.Extensions.Loading +* File: LoadingExtensions.cs +* +* LoadingExtensions.cs is part of VNLib.Plugins.Extensions.Loading which is part of the larger +* VNLib collection of libraries and utilities. +* +* VNLib.Plugins.Extensions.Loading is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* VNLib.Plugins.Extensions.Loading is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +*/ + +using System.Threading.Tasks; +using VNLib.Utils.Logging; +using System.Threading; + +namespace VNLib.Plugins.Extensions.Loading +{ + /// <summary> + /// Represents a low priority or long running work task to be done + /// and observed by a loaded plugin + /// </summary> + public interface IAsyncBackgroundWork + { + /// <summary> + /// Called when low priority work is ready to be run and its results + /// marshaled back to the plugin context + /// </summary> + /// <param name="pluginLog">The plugins default log provider</param> + /// <param name="exitToken">A token that signals when the plugin is unloading and work should be cancelled</param> + /// <returns>A task representing the low priority work to observed</returns> + Task DoWorkAsync(ILogProvider pluginLog, CancellationToken exitToken); + } +} diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/LoadingExtensions.cs b/lib/VNLib.Plugins.Extensions.Loading/src/LoadingExtensions.cs index 25dc4ec..743566d 100644 --- a/lib/VNLib.Plugins.Extensions.Loading/src/LoadingExtensions.cs +++ b/lib/VNLib.Plugins.Extensions.Loading/src/LoadingExtensions.cs @@ -38,6 +38,7 @@ using VNLib.Plugins.Essentials.Accounts; namespace VNLib.Plugins.Extensions.Loading { + /// <summary> /// Provides common loading (and unloading when required) extensions for plugins /// </summary> @@ -225,7 +226,7 @@ namespace VNLib.Plugins.Extensions.Loading /// <param name="delayMs">An optional startup delay for the operation</param> /// <returns>A task that completes when the deferred task completes </returns> /// <exception cref="ObjectDisposedException"></exception> - public static async Task DeferTask(this PluginBase plugin, Func<Task> asyncTask, int delayMs = 0) + public static async Task ObserveTask(this PluginBase plugin, Func<Task> asyncTask, int delayMs = 0) { /* * Motivation: @@ -266,6 +267,20 @@ namespace VNLib.Plugins.Extensions.Loading } } + + /// <summary> + /// Schedules work to begin after the specified delay to be observed by the plugin while + /// passing plugin specifie information. Exceptions are logged to the default plugin log + /// </summary> + /// <param name="plugin"></param> + /// <param name="work">The work to be observed</param> + /// <param name="delayMs">The time (in milliseconds) to delay dispatching the work item</param> + /// <returns>The task that represents the scheduled work</returns> + public static Task ObserveWork(this PluginBase plugin, IAsyncBackgroundWork work, int delayMs = 0) + { + return ObserveTask(plugin, () => work.DoWorkAsync(plugin.Log, plugin.UnloadToken), delayMs); + } + /// <summary> /// Registers an event to occur when the plugin is unloaded on a background thread /// and will cause the Plugin.Unload() method to block until the event completes @@ -292,10 +307,9 @@ namespace VNLib.Plugins.Extensions.Loading } //Registaer the task to cause the plugin to wait - return pbase.DeferTask(() => WaitForUnload(pbase, callback)); + return pbase.ObserveTask(() => WaitForUnload(pbase, callback)); } - private sealed class PluginLocalCache { private readonly PluginBase _plugin; @@ -356,7 +370,7 @@ namespace VNLib.Plugins.Extensions.Loading public void LoadSecret(PluginBase pbase) { - _ = pbase.DeferTask(() => LoadSecretInternal(pbase)); + _ = pbase.ObserveTask(() => LoadSecretInternal(pbase)); } private async Task LoadSecretInternal(PluginBase pbase) diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/RoutingExtensions.cs b/lib/VNLib.Plugins.Extensions.Loading/src/RoutingExtensions.cs index f27b3b3..c1c6bb6 100644 --- a/lib/VNLib.Plugins.Extensions.Loading/src/RoutingExtensions.cs +++ b/lib/VNLib.Plugins.Extensions.Loading/src/RoutingExtensions.cs @@ -30,6 +30,7 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using VNLib.Plugins.Extensions.Loading.Events; +using System.Net; namespace VNLib.Plugins.Extensions.Loading.Routing { @@ -50,42 +51,53 @@ namespace VNLib.Plugins.Extensions.Loading.Routing public static T Route<T>(this PluginBase plugin, string? pluginConfigPathName) where T : IEndpoint { Type endpointType = typeof(T); + + T endpoint; + //If the config attribute is not set, then ignore the config variables if (string.IsNullOrWhiteSpace(pluginConfigPathName)) { ConstructorInfo? constructor = endpointType.GetConstructor(new Type[] { typeof(PluginBase) }); + _ = constructor ?? throw new EntryPointNotFoundException($"No constructor found for {endpointType.Name}"); + //Create the new endpoint and pass the plugin instance - T endpoint = (T)constructor.Invoke(new object[] { plugin }); + endpoint = (T)constructor.Invoke(new object[] { plugin }); + //Register event handlers for the endpoint ScheduleIntervals(plugin, endpoint, endpointType, null); - //Route the endpoint - plugin.Route(endpoint); - - //Store ref to plugin for endpoint - _pluginRefs.Add(endpoint, plugin); - - return endpoint; } else { ConstructorInfo? constructor = endpointType.GetConstructor(new Type[] { typeof(PluginBase), typeof(IReadOnlyDictionary<string, JsonElement>) }); + //Make sure the constructor exists _ = constructor ?? throw new EntryPointNotFoundException($"No constructor found for {endpointType.Name}"); + //Get config variables for the endpoint IReadOnlyDictionary<string, JsonElement> conf = plugin.GetConfig(pluginConfigPathName); + //Create the new endpoint and pass the plugin instance along with the configuration object - T endpoint = (T)constructor.Invoke(new object[] { plugin, conf }); + endpoint = (T)constructor.Invoke(new object[] { plugin, conf }); + //Register event handlers for the endpoint ScheduleIntervals(plugin, endpoint, endpointType, conf); - //Route the endpoint - plugin.Route(endpoint); + } - //Store ref to plugin for endpoint - _pluginRefs.Add(endpoint, plugin); + //Route the endpoint + plugin.Route(endpoint); - return endpoint; + //Store ref to plugin for endpoint + _pluginRefs.Add(endpoint, plugin); + + //See if the endpoint is disposable + if (endpoint is IDisposable dis) + { + //Register dispose for unload + _ = plugin.RegisterForUnload(dis.Dispose); } + + return endpoint; } /// <summary> diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/VNLib.Plugins.Extensions.Loading.csproj b/lib/VNLib.Plugins.Extensions.Loading/src/VNLib.Plugins.Extensions.Loading.csproj index c31ae1c..a660a7e 100644 --- a/lib/VNLib.Plugins.Extensions.Loading/src/VNLib.Plugins.Extensions.Loading.csproj +++ b/lib/VNLib.Plugins.Extensions.Loading/src/VNLib.Plugins.Extensions.Loading.csproj @@ -28,7 +28,7 @@ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> <PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" /> - <PackageReference Include="VaultSharp" Version="1.7.1" /> + <PackageReference Include="VaultSharp" Version="1.12.2.1" /> </ItemGroup> <ItemGroup> diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/VaultSecrets.cs b/lib/VNLib.Plugins.Extensions.Loading/src/VaultSecrets.cs index d3bdf42..da6650a 100644 --- a/lib/VNLib.Plugins.Extensions.Loading/src/VaultSecrets.cs +++ b/lib/VNLib.Plugins.Extensions.Loading/src/VaultSecrets.cs @@ -78,6 +78,7 @@ namespace VNLib.Plugins.Extensions.Loading /// <exception cref="ObjectDisposedException"></exception> public static Task<SecretResult?> TryGetSecretAsync(this PluginBase plugin, string secretName) { + plugin.ThrowIfUnloaded(); //Get the secret from the config file raw string? rawSecret = TryGetSecretInternal(plugin, secretName); if (rawSecret == null) @@ -159,6 +160,7 @@ namespace VNLib.Plugins.Extensions.Loading /// <exception cref="ObjectDisposedException"></exception> public static Task<X509Certificate?> TryGetCertificateAsync(this PluginBase plugin, string secretName) { + plugin.ThrowIfUnloaded(); //Get the secret from the config file raw string? rawSecret = TryGetSecretInternal(plugin, secretName); if (rawSecret == null) |