using System; using Svrnty.CQRS.Events.Abstractions.Delivery; using Svrnty.CQRS.Events.Delivery; using Svrnty.CQRS.Events.Abstractions.EventStore; using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Svrnty.CQRS.Events.Abstractions; using Svrnty.CQRS.Events.Abstractions.Subscriptions; namespace Svrnty.CQRS.Events.Subscriptions; /// /// Service collection extensions for persistent subscriptions. /// public static class ServiceCollectionExtensions { /// /// Add persistent subscription support to the service collection. /// /// The service collection. /// If true, uses in-memory store. Otherwise, expects a persistent store to be registered separately. /// If true, enables background service for automatic event delivery to subscriptions. /// The service collection for chaining. public static IServiceCollection AddPersistentSubscriptions( this IServiceCollection services, bool useInMemoryStore = true, bool enableBackgroundDelivery = true) { // Register subscription manager services.AddSingleton(); // Register Phase 8 event delivery service services.AddSingleton(); // Register in-memory store if requested if (useInMemoryStore) { services.AddSingleton(); } // Decorate the main IEventDeliveryService with Phase 8 integration // This wraps the existing event delivery to also notify persistent subscriptions DecorateEventDeliveryService(services); // Register background delivery service if requested // NOTE: SubscriptionDeliveryHostedService is temporarily disabled pending redesign // to work with ICorrelatedEvent which doesn't have Sequence/EventType properties // if (enableBackgroundDelivery) // { // services.AddHostedService(); // } return services; } private static void DecorateEventDeliveryService(IServiceCollection services) { // Find the existing IEventDeliveryService registration var existingDescriptor = services.FirstOrDefault(d => d.ServiceType == typeof(IEventDeliveryService)); if (existingDescriptor == null) { // If not registered yet, this will be called before AddSvrntyEvents // The decorator will be registered anyway and will work when the service is added return; } // Remove the existing registration services.Remove(existingDescriptor); // Re-register the original implementation with a different service type services.Add(ServiceDescriptor.Describe( typeof(Svrnty.CQRS.Events.Delivery.EventDeliveryService), existingDescriptor.ImplementationType!, existingDescriptor.Lifetime)); // Register the decorator as IEventDeliveryService services.Add(ServiceDescriptor.Describe( typeof(IEventDeliveryService), sp => { var inner = sp.GetRequiredService(); var persistentDeliveryService = sp.GetService(); var subscriptionStore = sp.GetService(); var logger = sp.GetRequiredService>(); return new PersistentSubscriptionDeliveryDecorator(inner, persistentDeliveryService, subscriptionStore, logger); }, existingDescriptor.Lifetime)); } }