diff options
Diffstat (limited to 'lib')
4 files changed, 76 insertions, 19 deletions
diff --git a/lib/VNLib.Plugins.Extensions.Loading.Sql/src/SqlDbConnectionLoader.cs b/lib/VNLib.Plugins.Extensions.Loading.Sql/src/SqlDbConnectionLoader.cs index 0ea60d6..daddddb 100644 --- a/lib/VNLib.Plugins.Extensions.Loading.Sql/src/SqlDbConnectionLoader.cs +++ b/lib/VNLib.Plugins.Extensions.Loading.Sql/src/SqlDbConnectionLoader.cs @@ -37,6 +37,7 @@ using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using VNLib.Utils.Logging; +using VNLib.Utils.Resources; using VNLib.Utils.Extensions; using VNLib.Plugins.Extensions.Loading.Sql.DatabaseBuilder; using VNLib.Plugins.Extensions.Loading.Sql.DatabaseBuilder.Helpers; @@ -51,9 +52,13 @@ namespace VNLib.Plugins.Extensions.Loading.Sql { public const string SQL_CONFIG_KEY = "sql"; public const string DB_PASSWORD_KEY = "db_password"; + public const string EXTERN_SQL_LIB_KEY = "custom_assembly"; + + public const string EXTERN_LIB_GET_CONN_FUNC_NAME = "GetDbConnections"; private const string MAX_LEN_BYPASS_KEY = "MaxLen"; - private const string TIMESTAMP_BYPASS = "TimeStamp"; + private const string TIMESTAMP_BYPASS = "TimeStamp"; + /// <summary> /// Gets (or loads) the ambient sql connection factory for the current plugin @@ -84,7 +89,7 @@ namespace VNLib.Plugins.Extensions.Loading.Sql { static IAsyncLazy<Func<DbConnection>> FactoryLoader(PluginBase plugin) { - return GetFactoryLoaderAsync(plugin).AsLazy(); + return Task.Run(() => GetFactoryLoaderAsync(plugin)).AsLazy(); } plugin.ThrowIfUnloaded(); @@ -96,6 +101,17 @@ namespace VNLib.Plugins.Extensions.Loading.Sql private async static Task<Func<DbConnection>> GetFactoryLoaderAsync(PluginBase plugin) { IConfigScope sqlConf = plugin.GetConfig(SQL_CONFIG_KEY); + + //See if the user wants to use a custom assembly + if (sqlConf.ContainsKey(EXTERN_SQL_LIB_KEY)) + { + string dllPath = sqlConf.GetRequiredProperty(EXTERN_SQL_LIB_KEY, k => k.GetString()!); + + //Load the library and get instance + object dbProvider = plugin.CreateServiceExternal<object>(dllPath); + + return ManagedLibrary.GetMethod<Func<DbConnection>>(dbProvider, EXTERN_LIB_GET_CONN_FUNC_NAME); + } //Get the db-type string? type = sqlConf.GetPropString("db_type"); @@ -270,8 +286,11 @@ namespace VNLib.Plugins.Extensions.Loading.Sql //Invoke ontbCreating to setup the dbBuilder dbCreator.OnDatabaseCreating(builder, state); + //Wait for the connection factory to load + Func<DbConnection> dbConFactory = await GetConnectionFactoryAsync(plugin); + //Create a new db connection - await using DbConnection connection = (await plugin.GetConnectionFactoryAsync()).Invoke(); + await using DbConnection connection = dbConFactory(); //Get the abstract database from the connection type IDBCommandGenerator cb = connection.GetCmGenerator(); diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/AssemblyLoader.cs b/lib/VNLib.Plugins.Extensions.Loading/src/AssemblyLoader.cs index cd2dbad..49ef4b3 100644 --- a/lib/VNLib.Plugins.Extensions.Loading/src/AssemblyLoader.cs +++ b/lib/VNLib.Plugins.Extensions.Loading/src/AssemblyLoader.cs @@ -96,9 +96,9 @@ namespace VNLib.Plugins.Extensions.Loading if (disposing) { //If the instance is disposable, call its dispose method on unload - if (_instance.IsValueCreated && _instance.Value is IDisposable) + if (_instance.IsValueCreated && _instance.Value is IDisposable disposable) { - (_instance.Value as IDisposable)?.Dispose(); + disposable.Dispose(); } } diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/LoadingExtensions.cs b/lib/VNLib.Plugins.Extensions.Loading/src/LoadingExtensions.cs index 8432cde..98f8f6c 100644 --- a/lib/VNLib.Plugins.Extensions.Loading/src/LoadingExtensions.cs +++ b/lib/VNLib.Plugins.Extensions.Loading/src/LoadingExtensions.cs @@ -134,7 +134,7 @@ namespace VNLib.Plugins.Extensions.Loading } /// <summary> - /// Loads an assembly into the current plugin's load context and will unload when disposed + /// Loads a managed assembly into the current plugin's load context and will unload when disposed /// or the plugin is unloaded from the host application. /// </summary> /// <typeparam name="T">The desired exported type to load from the assembly</typeparam> @@ -160,7 +160,7 @@ namespace VNLib.Plugins.Extensions.Loading { //Get the file path for the assembly string asmFile = GetAssetFilePath(plugin, assemblyName, dirSearchOption) - ?? throw new FileNotFoundException($"Failed to load custom assembly {assemblyName} from plugin directory"); + ?? throw new FileNotFoundException($"Failed to find custom assembly {assemblyName} from plugin directory"); //Get the plugin's load context if not explicitly supplied explictAlc ??= GetPluginLoadContext(); @@ -172,7 +172,40 @@ namespace VNLib.Plugins.Extensions.Loading //Load the assembly return AssemblyLoader<T>.Load(asmFile, explictAlc, plugin.UnloadToken); } - + + /// <summary> + /// Loads a managed assembly into the current plugin's load context and will unload when disposed + /// or the plugin is unloaded from the host application. + /// </summary> + /// <param name="plugin"></param> + /// <param name="assemblyName">The name of the assembly (ex: 'file.dll') to search for</param> + /// <param name="dirSearchOption">Directory/file search option</param> + /// <param name="explictAlc"> + /// Explicitly define an <see cref="AssemblyLoadContext"/> to load the assmbly, and it's dependencies + /// into. If null, uses the plugin's alc. + /// </param> + /// <returns>The <see cref="AssemblyLoader{T}"/> managing the loaded assmbly in the current AppDomain</returns> + /// <exception cref="ArgumentNullException"></exception> + /// <exception cref="FileNotFoundException"></exception> + /// <remarks> + /// The assembly is searched within the 'assets' directory specified in the plugin config + /// or the global plugins ('path' key) directory if an assets directory is not defined. + /// </remarks> + public static ManagedLibrary LoadAssembly( + this PluginBase plugin, + string assemblyName, + SearchOption dirSearchOption = SearchOption.AllDirectories, + AssemblyLoadContext? explictAlc = null) + { + /* + * Using an assembly loader instance instead of managed library, so it respects + * the plugin's unload events. Returning the managed library instance will + * hide the overloads that would cause possible type load issues, so using + * an object as the generic type parameter shouldn't be an issue. + */ + return LoadAssembly<object>(plugin, assemblyName, dirSearchOption, explictAlc); + } + /// <summary> /// Gets the current plugin's <see cref="AssemblyLoadContext"/>. /// </summary> @@ -379,7 +412,7 @@ namespace VNLib.Plugins.Extensions.Loading * Loading it on the plugin will also cause it be cleaned up when the plugin * is unloaded. */ - ManagedLibrary manLib = _assemblyCache.GetOrAdd(assemblyDllName, (name) => plugin.LoadAssembly<T>(name, search, defaultCtx)); + ManagedLibrary manLib = _assemblyCache.GetOrAdd(assemblyDllName, (name) => LoadAssembly<T>(plugin, name, search, defaultCtx)); Type[] matchingTypes = manLib.TryGetAllMatchingTypes<T>().ToArray(); //try to get the first type that has the extern attribute, or fall back to the first public & concrete type @@ -592,6 +625,7 @@ namespace VNLib.Plugins.Extensions.Loading } object service; + ConstructorInfo? constructor; try { @@ -604,7 +638,7 @@ namespace VNLib.Plugins.Extensions.Loading } //Get the constructor for required or available config - ConstructorInfo? constructor = serviceType.GetConstructor(new Type[] { typeof(PluginBase), typeof(IConfigScope) }); + constructor = serviceType.GetConstructor(new Type[] { typeof(PluginBase), typeof(IConfigScope) }); //Make sure the constructor exists _ = constructor ?? throw new MissingMemberException($"No constructor found for {serviceType.Name}"); @@ -612,17 +646,21 @@ namespace VNLib.Plugins.Extensions.Loading //Call constructore service = constructor.Invoke(new object[2] { plugin, config }); } - else + else if((constructor = serviceType.GetConstructor(new Type[] { typeof(PluginBase) })) != null) { - //Get the constructor - ConstructorInfo? constructor = serviceType.GetConstructor(new Type[] { typeof(PluginBase) }); - - //Make sure the constructor exists - _ = constructor ?? throw new MissingMemberException($"No constructor found for {serviceType.Name}"); - - //Call constructore + //Call constructor service = constructor.Invoke(new object[1] { plugin }); } + //try to get empty constructor + else if ((constructor = serviceType.GetConstructor(Array.Empty<Type>())) != null) + { + //Invoked empty constructor + service = constructor.Invoke(null); + } + else + { + throw new MissingMemberException($"No constructor found for {serviceType.Name}"); + } } catch(TargetInvocationException te) when (te.InnerException != null) { diff --git a/lib/VNLib.Plugins.Extensions.Loading/src/Secrets/SecretResult.cs b/lib/VNLib.Plugins.Extensions.Loading/src/Secrets/SecretResult.cs index c1e6b3d..2c231b7 100644 --- a/lib/VNLib.Plugins.Extensions.Loading/src/Secrets/SecretResult.cs +++ b/lib/VNLib.Plugins.Extensions.Loading/src/Secrets/SecretResult.cs @@ -54,7 +54,7 @@ namespace VNLib.Plugins.Extensions.Loading ///<inheritdoc/> protected override void Free() { - MemoryUtil.InitializeBlock(_secretChars.AsSpan()); + MemoryUtil.InitializeBlock(_secretChars); } internal static SecretResult ToSecret(string? result) |