diff options
author | vnugent <public@vaughnnugent.com> | 2023-03-09 01:48:28 -0500 |
---|---|---|
committer | vnugent <public@vaughnnugent.com> | 2023-03-09 01:48:28 -0500 |
commit | 5ddef0fcb742e77b99a0e17015d2eea0a1d4131a (patch) | |
tree | c1c88284b11b70d9f373215d8d54e8a168cc5700 /lib/Plugins.Runtime/src/LoaderExtensions.cs | |
parent | dab71d5597fdfbe71f6ac310a240835716e952a5 (diff) |
Omega cache, session, and account provider complete overhaul
Diffstat (limited to 'lib/Plugins.Runtime/src/LoaderExtensions.cs')
-rw-r--r-- | lib/Plugins.Runtime/src/LoaderExtensions.cs | 174 |
1 files changed, 112 insertions, 62 deletions
diff --git a/lib/Plugins.Runtime/src/LoaderExtensions.cs b/lib/Plugins.Runtime/src/LoaderExtensions.cs index 795dcf5..13fbb11 100644 --- a/lib/Plugins.Runtime/src/LoaderExtensions.cs +++ b/lib/Plugins.Runtime/src/LoaderExtensions.cs @@ -1,5 +1,5 @@ /* -* Copyright (c) 2022 Vaughn Nugent +* Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Runtime @@ -23,98 +23,148 @@ */ using System; -using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Text.Json; +using System.Threading.Tasks; + namespace VNLib.Plugins.Runtime { + /// <summary> + /// Contains extension methods for PluginLoader library + /// </summary> public static class LoaderExtensions { - /// <summary> - /// Searches all plugins within the current loader for a - /// single plugin that derrives the specified type - /// </summary> - /// <typeparam name="T">The type the plugin must derrive from</typeparam> - /// <param name="loader"></param> - /// <returns>The instance of the plugin that derrives from the specified type</returns> - public static LivePlugin? GetExposedPlugin<T>(this RuntimePluginLoader loader) + /* + * Class that manages a collection registration for a specific type + * dependency, and redirects the event calls for the consumed service + */ + private sealed class TypedRegistration<T> : IPluginEventListener where T: class { - return loader.LivePlugins - .Where(static pl => typeof(T).IsAssignableFrom(pl.Plugin!.GetType())) - .SingleOrDefault(); + private readonly ITypedPluginConsumer<T> _consumerEvents; + private readonly object? _userState; + + private T? _service; + private readonly Type _type; + + public TypedRegistration(ITypedPluginConsumer<T> consumerEvents, Type type) + { + _consumerEvents = consumerEvents; + _type = type; + } + + + public void OnPluginLoaded(PluginController controller, object? state) + { + //Get the service from the loaded plugins + T service = controller.Plugins + .Where(pl => _type.IsAssignableFrom(pl.PluginType)) + .Select(static pl => (T)pl.Plugin!) + .First(); + + //Call load with the exported type + _consumerEvents.OnLoad(service, _userState); + + //Store for unload + _service = service; + } + + public void OnPluginUnloaded(PluginController controller, object? state) + { + //Unload + _consumerEvents.OnUnload(_service!, _userState); + _service = null; + } } /// <summary> - /// Searches all plugins within the current loader for a - /// single plugin that derrives the specified type + /// Registers a plugin even handler for the current <see cref="PluginController"/> + /// for a specific type. /// </summary> - /// <typeparam name="T">The type the plugin must derrive from</typeparam> - /// <param name="loader"></param> - /// <returns>The instance of your custom type casted, or null if not found or could not be casted</returns> - public static T? GetExposedTypeFromPlugin<T>(this RuntimePluginLoader loader) where T: class + /// <typeparam name="T"></typeparam> + /// <param name="collection"></param> + /// <param name="consumer">The typed plugin instance event consumer</param> + /// <returns>A <see cref="PluginEventRegistration"/> handle that manages this event registration</returns> + /// <exception cref="ArgumentException"></exception> + public static PluginEventRegistration RegisterForType<T>(this PluginController collection, ITypedPluginConsumer<T> consumer) where T: class { - LivePlugin? plugin = loader.LivePlugins - .Where(static pl => typeof(T).IsAssignableFrom(pl.Plugin!.GetType())) - .SingleOrDefault(); + Type serviceType = typeof(T); - return plugin?.Plugin as T; + //Confim the type is exposed by this collection + if(!ExposesType(collection, serviceType)) + { + throw new ArgumentException("The requested type is not exposed in this assembly"); + } + + //Create new typed listener + TypedRegistration<T> reg = new(consumer, serviceType); + + //register event handler + return Register(collection, reg, null); } /// <summary> - /// Registers a listener delegate method to invoke when the - /// current <see cref="RuntimePluginLoader"/> is reloaded, and passes - /// the new instance of the specified type + /// Registers a handler to listen for plugin load/unload events /// </summary> - /// <typeparam name="T">The single plugin type to register a listener for</typeparam> - /// <param name="loader"></param> - /// <param name="reloaded">The delegate method to invoke when the loader has reloaded plugins</param> /// <exception cref="ArgumentNullException"></exception> - public static bool RegisterListenerForSingle<T>(this RuntimePluginLoader loader, Action<T, T> reloaded) where T: class + /// <returns>A <see cref="PluginEventRegistration"/> handle that will unregister the listener when disposed</returns> + public static PluginEventRegistration Register(this IPluginEventRegistrar reg, IPluginEventListener listener, object? state = null) { - _ = reloaded ?? throw new ArgumentNullException(nameof(reloaded)); + reg.Register(listener, state); + return new(reg, listener); + } - //try to get the casted type from the loader - T? current = loader.GetExposedTypeFromPlugin<T>(); + /// <summary> + /// Loads the configuration file into its <see cref="JsonDocument"/> format + /// for reading. + /// </summary> + /// <param name="loader"></param> + /// <returns>A new <see cref="JsonDocument"/> of the loaded configuration file</returns> + public static async Task<JsonDocument> GetPluginConfigAsync(this RuntimePluginLoader loader) + { + //Open and read the config file + await using FileStream confStream = File.OpenRead(loader.PluginConfigPath); - if (current == null) - { - return false; - } - else + JsonDocumentOptions jdo = new() { - loader.Reloaded += delegate (object? sender, EventArgs args) - { - RuntimePluginLoader wpl = (sender as RuntimePluginLoader)!; - //Get the new loaded type - T newT = (wpl.GetExposedPlugin<T>()!.Plugin as T)!; - //Invoke reloaded action - reloaded(current, newT); - //update the new current instance - current = newT; - }; - - return true; - } + AllowTrailingCommas = true, + CommentHandling = JsonCommentHandling.Skip, + }; + + //parse the plugin config file + return await JsonDocument.ParseAsync(confStream, jdo); } /// <summary> - /// Gets all endpoints exposed by all exported plugin instances - /// within the current loader + /// Determines if the current <see cref="PluginController"/> + /// exposes the desired type on is <see cref="IPlugin"/> + /// type. /// </summary> - /// <param name="loader"></param> - /// <returns>An enumeration of all endpoints</returns> - public static IEnumerable<IEndpoint> GetEndpoints(this RuntimePluginLoader loader) => loader.LivePlugins.SelectMany(static pl => pl.Plugin!.GetEndpoints()); + /// <param name="collection"></param> + /// <param name="type">The desired type to request</param> + /// <returns>True if the plugin exposes the desired type, false otherwise</returns> + public static bool ExposesType(this PluginController collection, Type type) + { + return collection.Plugins + .Where(pl => type.IsAssignableFrom(pl.PluginType)) + .Any(); + } /// <summary> - /// Determines if any loaded plugin types exposes an instance of the - /// specified type + /// Searches all plugins within the current loader for a + /// single plugin that derrives the specified type /// </summary> - /// <typeparam name="T"></typeparam> + /// <typeparam name="T">The type the plugin must derrive from</typeparam> /// <param name="loader"></param> - /// <returns>True if any plugin instance exposes a the specified type, false otherwise</returns> - public static bool ExposesType<T>(this RuntimePluginLoader loader) where T : class + /// <returns>The instance of your custom type casted, or null if not found or could not be casted</returns> + public static T? GetExposedTypes<T>(this PluginController collection) where T: class { - return loader.LivePlugins.Any(static pl => typeof(T).IsAssignableFrom(pl.Plugin?.GetType())); + LivePlugin? plugin = collection.Plugins + .Where(static pl => typeof(T).IsAssignableFrom(pl.PluginType)) + .SingleOrDefault(); + + return plugin?.Plugin as T; } } } |