diff options
author | vman <public@vaughnnugent.com> | 2022-12-28 14:15:04 -0500 |
---|---|---|
committer | vman <public@vaughnnugent.com> | 2022-12-28 14:15:04 -0500 |
commit | 0c2fa662f60cf8b6b771fef3ff4c740eae17a83d (patch) | |
tree | 91495d460ceb12fba8cc274e77a8cbf4019c028d /VNLib.Plugins.Extensions.Loading/AssemblyLoader.cs | |
parent | 8b5f3eebb9f8d9bd55e922a809ffa3bd52e33401 (diff) |
Global cache client, asm loading, plugin local cache, and event managment
Diffstat (limited to 'VNLib.Plugins.Extensions.Loading/AssemblyLoader.cs')
-rw-r--r-- | VNLib.Plugins.Extensions.Loading/AssemblyLoader.cs | 68 |
1 files changed, 53 insertions, 15 deletions
diff --git a/VNLib.Plugins.Extensions.Loading/AssemblyLoader.cs b/VNLib.Plugins.Extensions.Loading/AssemblyLoader.cs index 5da16ec..a53bb0a 100644 --- a/VNLib.Plugins.Extensions.Loading/AssemblyLoader.cs +++ b/VNLib.Plugins.Extensions.Loading/AssemblyLoader.cs @@ -26,9 +26,11 @@ using System; using System.Linq; using System.Threading; using System.Reflection; +using System.Runtime.Loader; +using System.Collections.Generic; using McMaster.NETCore.Plugins; -using System.Runtime.Loader; + using VNLib.Utils.Resources; namespace VNLib.Plugins.Extensions.Loading @@ -47,7 +49,6 @@ namespace VNLib.Plugins.Extensions.Loading public class AssemblyLoader<T> : OpenResourceHandle<T> { private readonly PluginLoader _loader; - private readonly Type _typeInfo; private readonly CancellationTokenRegistration _reg; private readonly Lazy<T> _instance; @@ -58,13 +59,13 @@ namespace VNLib.Plugins.Extensions.Loading private AssemblyLoader(PluginLoader loader, in CancellationToken unloadToken) { - _typeInfo = typeof(T); _loader = loader; //Init lazy loader _instance = new(LoadAndGetExportedType, LazyThreadSafetyMode.PublicationOnly); //Register dispose _reg = unloadToken.Register(Dispose); } + /// <summary> /// Loads the default assembly and gets the expected export type, /// creates a new instance, and calls its parameterless constructor @@ -75,17 +76,36 @@ namespace VNLib.Plugins.Extensions.Loading { //Load the assembly Assembly asm = _loader.LoadDefaultAssembly(); - + + Type resourceType = typeof(T); + //See if the type is exported Type exp = (from type in asm.GetExportedTypes() - where _typeInfo.IsAssignableFrom(type) + where resourceType.IsAssignableFrom(type) select type) .FirstOrDefault() - ?? throw new EntryPointNotFoundException($"Imported assembly does not export type {_typeInfo.FullName}"); + ?? throw new EntryPointNotFoundException($"Imported assembly does not export desired type {resourceType.FullName}"); //Create instance return (T)Activator.CreateInstance(exp)!; } + /// <summary> + /// Creates a method delegate for the given method name from + /// the instance wrapped by the current loader + /// </summary> + /// <typeparam name="TDelegate"></typeparam> + /// <param name="methodName">The name of the method to recover</param> + /// <returns>The delegate method wrapper if found, null otherwise</returns> + /// <exception cref="ArgumentNullException"></exception> + /// <exception cref="AmbiguousMatchException"></exception> + public TDelegate? TryGetMethod<TDelegate>(string methodName) where TDelegate : Delegate + { + //get the type info of the actual resource + return Resource!.GetType() + .GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance) + ?.CreateDelegate<TDelegate>(Resource); + } + ///<inheritdoc/> protected override void Free() { @@ -105,18 +125,36 @@ namespace VNLib.Plugins.Extensions.Loading /// <param name="unloadToken">The plugin unload token</param> internal static AssemblyLoader<T> Load(string assemblyName, CancellationToken unloadToken) { - PluginConfig conf = new(assemblyName) + Assembly executingAsm = Assembly.GetExecutingAssembly(); + AssemblyLoadContext currentCtx = AssemblyLoadContext.GetLoadContext(executingAsm) ?? throw new InvalidOperationException("Could not get default assembly load context"); + + List<Type> shared = new () { - IsUnloadable = true, - EnableHotReload = false, - PreferSharedTypes = true, - DefaultContext = AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()) ?? AssemblyLoadContext.Default + typeof(T), + typeof(PluginBase), }; + + //Add all types that have already been loaded + shared.AddRange(currentCtx.Assemblies.SelectMany(s => s.GetExportedTypes())); - PluginLoader loader = new(conf); - - //Add the assembly the type originaged from - conf.SharedAssemblies.Add(typeof(T).Assembly.GetName()); + PluginLoader loader = PluginLoader.CreateFromAssemblyFile(assemblyName, + currentCtx.IsCollectible, + shared.ToArray(), + conf => + { + + /* + * Load context is required to be set to the executing assembly's load context + * because it is controlled by the host, so this loader should be considered a + * a "child" collection of assemblies + */ + conf.DefaultContext = currentCtx; + + conf.PreferSharedTypes = true; + + //Share utils asm + conf.SharedAssemblies.Add(typeof(Utils.Memory.Memory).Assembly.GetName()); + }); return new(loader, in unloadToken); } |