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() { } } } }