using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Cryptography;
using StellaOps.Cryptography.PluginLoader;
namespace StellaOps.Cryptography.DependencyInjection;
///
/// DI extension methods for configuration-driven crypto plugin loading.
///
public static class CryptoPluginServiceCollectionExtensions
{
///
/// Registers crypto providers using configuration-driven plugin loading.
/// Replaces hardcoded provider registrations with dynamic plugin loader.
///
/// Service collection.
/// Application configuration.
/// Optional plugin configuration action.
/// The service collection.
public static IServiceCollection AddStellaOpsCryptoWithPlugins(
this IServiceCollection services,
IConfiguration configuration,
Action? configurePlugins = null)
{
ArgumentNullException.ThrowIfNull(services);
ArgumentNullException.ThrowIfNull(configuration);
// Bind plugin configuration from appsettings
services.Configure(options =>
{
configuration.GetSection("StellaOps:Crypto:Plugins").Bind(options);
configurePlugins?.Invoke(options);
});
// Register compliance options (reuse existing code)
services.TryAddSingleton>(sp =>
{
var config = sp.GetService();
var options = new CryptoComplianceOptions();
config?.GetSection(CryptoComplianceOptions.SectionKey).Bind(options);
options.ApplyEnvironmentOverrides();
return new StaticComplianceOptionsMonitor(options);
});
services.TryAddSingleton();
services.TryAddSingleton();
services.TryAddSingleton();
// Register plugin loader and load providers dynamically
services.TryAddSingleton(sp =>
{
var pluginConfig = sp.GetRequiredService>().Value;
var logger = sp.GetService>();
return new CryptoPluginLoader(pluginConfig, logger);
});
// Load all configured crypto providers
services.TryAddSingleton(sp =>
{
var loader = sp.GetRequiredService();
return loader.LoadProviders();
});
// Register each loaded provider as ICryptoProvider
services.TryAddSingleton>(sp =>
{
return sp.GetRequiredService>();
});
// Register crypto provider registry with loaded providers
services.TryAddSingleton(sp =>
{
var providers = sp.GetRequiredService>();
var options = sp.GetService>();
IEnumerable? preferred = options?.CurrentValue?.ResolvePreferredProviders();
return new CryptoProviderRegistry(providers, preferred);
});
return services;
}
///
/// Registers crypto providers with plugin loading and compliance profile configuration.
///
/// Service collection.
/// Application configuration.
/// Optional plugin configuration.
/// Optional compliance configuration.
/// The service collection.
public static IServiceCollection AddStellaOpsCryptoWithPluginsAndCompliance(
this IServiceCollection services,
IConfiguration configuration,
Action? configurePlugins = null,
Action? configureCompliance = null)
{
ArgumentNullException.ThrowIfNull(services);
ArgumentNullException.ThrowIfNull(configuration);
// Bind compliance options from configuration
services.Configure(options =>
{
configuration.GetSection(CryptoComplianceOptions.SectionKey).Bind(options);
configureCompliance?.Invoke(options);
options.ApplyEnvironmentOverrides();
});
// Register base crypto services with plugin loading
services.AddStellaOpsCryptoWithPlugins(configuration, configurePlugins);
return services;
}
///
/// Helper class for static options monitoring.
///
private sealed class StaticComplianceOptionsMonitor : IOptionsMonitor
{
private readonly CryptoComplianceOptions _options;
public StaticComplianceOptionsMonitor(CryptoComplianceOptions options)
=> _options = options;
public CryptoComplianceOptions CurrentValue => _options;
public CryptoComplianceOptions Get(string? name) => _options;
public IDisposable OnChange(Action listener)
=> NullDisposable.Instance;
private sealed class NullDisposable : IDisposable
{
public static readonly NullDisposable Instance = new();
public void Dispose() { }
}
}
}