aboutsummaryrefslogtreecommitdiff
path: root/lib/Plugins.Runtime/src/LoaderExtensions.cs
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-03-09 01:48:28 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2023-03-09 01:48:28 -0500
commit5ddef0fcb742e77b99a0e17015d2eea0a1d4131a (patch)
treec1c88284b11b70d9f373215d8d54e8a168cc5700 /lib/Plugins.Runtime/src/LoaderExtensions.cs
parentdab71d5597fdfbe71f6ac310a240835716e952a5 (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.cs174
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;
}
}
}