From 5ddef0fcb742e77b99a0e17015d2eea0a1d4131a Mon Sep 17 00:00:00 2001 From: vnugent Date: Thu, 9 Mar 2023 01:48:28 -0500 Subject: Omega cache, session, and account provider complete overhaul --- lib/Plugins.Runtime/src/LoaderExtensions.cs | 174 ++++++++++++++++++---------- 1 file changed, 112 insertions(+), 62 deletions(-) (limited to 'lib/Plugins.Runtime/src/LoaderExtensions.cs') 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 { + /// + /// Contains extension methods for PluginLoader library + /// public static class LoaderExtensions { - /// - /// Searches all plugins within the current loader for a - /// single plugin that derrives the specified type - /// - /// The type the plugin must derrive from - /// - /// The instance of the plugin that derrives from the specified type - public static LivePlugin? GetExposedPlugin(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 : IPluginEventListener where T: class { - return loader.LivePlugins - .Where(static pl => typeof(T).IsAssignableFrom(pl.Plugin!.GetType())) - .SingleOrDefault(); + private readonly ITypedPluginConsumer _consumerEvents; + private readonly object? _userState; + + private T? _service; + private readonly Type _type; + + public TypedRegistration(ITypedPluginConsumer 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; + } } /// - /// Searches all plugins within the current loader for a - /// single plugin that derrives the specified type + /// Registers a plugin even handler for the current + /// for a specific type. /// - /// The type the plugin must derrive from - /// - /// The instance of your custom type casted, or null if not found or could not be casted - public static T? GetExposedTypeFromPlugin(this RuntimePluginLoader loader) where T: class + /// + /// + /// The typed plugin instance event consumer + /// A handle that manages this event registration + /// + public static PluginEventRegistration RegisterForType(this PluginController collection, ITypedPluginConsumer 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 reg = new(consumer, serviceType); + + //register event handler + return Register(collection, reg, null); } /// - /// Registers a listener delegate method to invoke when the - /// current is reloaded, and passes - /// the new instance of the specified type + /// Registers a handler to listen for plugin load/unload events /// - /// The single plugin type to register a listener for - /// - /// The delegate method to invoke when the loader has reloaded plugins /// - public static bool RegisterListenerForSingle(this RuntimePluginLoader loader, Action reloaded) where T: class + /// A handle that will unregister the listener when disposed + 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(); + /// + /// Loads the configuration file into its format + /// for reading. + /// + /// + /// A new of the loaded configuration file + public static async Task 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()!.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); } /// - /// Gets all endpoints exposed by all exported plugin instances - /// within the current loader + /// Determines if the current + /// exposes the desired type on is + /// type. /// - /// - /// An enumeration of all endpoints - public static IEnumerable GetEndpoints(this RuntimePluginLoader loader) => loader.LivePlugins.SelectMany(static pl => pl.Plugin!.GetEndpoints()); + /// + /// The desired type to request + /// True if the plugin exposes the desired type, false otherwise + public static bool ExposesType(this PluginController collection, Type type) + { + return collection.Plugins + .Where(pl => type.IsAssignableFrom(pl.PluginType)) + .Any(); + } /// - /// 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 /// - /// + /// The type the plugin must derrive from /// - /// True if any plugin instance exposes a the specified type, false otherwise - public static bool ExposesType(this RuntimePluginLoader loader) where T : class + /// The instance of your custom type casted, or null if not found or could not be casted + public static T? GetExposedTypes(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; } } } -- cgit