aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/VNLib.Plugins.Extensions.Loading.Sql/src/SqlDbConnectionLoader.cs25
-rw-r--r--lib/VNLib.Plugins.Extensions.Loading/src/AssemblyLoader.cs4
-rw-r--r--lib/VNLib.Plugins.Extensions.Loading/src/LoadingExtensions.cs64
-rw-r--r--lib/VNLib.Plugins.Extensions.Loading/src/Secrets/SecretResult.cs2
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)