using System;
using Svrnty.CQRS.Events.Abstractions.Notifications;
using Svrnty.CQRS.Events.Abstractions.Delivery;
using Svrnty.CQRS.Events.Delivery;
using Svrnty.CQRS.Events.Abstractions.EventStore;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Svrnty.CQRS.Events.Abstractions;
using Svrnty.CQRS.Events.Abstractions.Subscriptions;
namespace Svrnty.CQRS.Events.Subscriptions;
///
/// Decorator that integrates Phase 8 persistent subscription delivery with the existing event delivery pipeline.
/// This wraps the default IEventDeliveryService and adds SignalR/gRPC-based delivery to active persistent subscriptions.
///
///
///
/// Integration Point:
/// This decorator is registered in the DI container when Phase 8 is enabled, wrapping the default EventDeliveryService.
///
///
/// Responsibilities:
/// - Delegates to the wrapped IEventDeliveryService for standard subscription management
/// - Delivers events to active persistent subscriptions via IPersistentSubscriptionDeliveryService
/// - Pushes events to connected SignalR and gRPC clients in real-time
/// - Tracks sequence numbers for catch-up on reconnect
///
///
public sealed class PersistentSubscriptionDeliveryDecorator : IEventDeliveryService
{
private readonly IEventDeliveryService _inner;
private readonly IPersistentSubscriptionDeliveryService? _persistentDeliveryService;
private readonly IPersistentSubscriptionStore? _subscriptionStore;
private readonly ILogger _logger;
public PersistentSubscriptionDeliveryDecorator(
IEventDeliveryService inner,
IPersistentSubscriptionDeliveryService? persistentDeliveryService,
IPersistentSubscriptionStore? subscriptionStore,
ILogger logger)
{
_inner = inner ?? throw new ArgumentNullException(nameof(inner));
_persistentDeliveryService = persistentDeliveryService;
_subscriptionStore = subscriptionStore;
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task DeliverEventAsync(ICorrelatedEvent @event, long sequence, CancellationToken cancellationToken = default)
{
// First, delegate to the wrapped service for standard processing
await _inner.DeliverEventAsync(@event, sequence, cancellationToken);
// Then, deliver to Phase 8 persistent subscriptions if enabled
if (_persistentDeliveryService != null)
{
try
{
var deliveredCount = await _persistentDeliveryService.DeliverEventAsync(
@event.CorrelationId,
@event,
sequence,
cancellationToken);
if (deliveredCount > 0)
{
_logger.LogDebug(
"Delivered event {EventType} (sequence {Sequence}) to {Count} persistent subscription(s)",
@event.GetType().Name,
sequence,
deliveredCount);
}
// Push events to connected gRPC/SignalR clients via event notifiers
// This happens after state updates so clients receive events immediately
if (_subscriptionStore != null)
{
// Note: Event notifiers (gRPC, SignalR) are called by EventEmitter via IEventNotifier
// This is handled separately in the event emission pipeline
// We could optionally call notifiers here as well for immediate push
}
}
catch (Exception ex)
{
// Log but don't fail the entire delivery if Phase 8 delivery fails
_logger.LogError(
ex,
"Error delivering event {EventType} (sequence {Sequence}) to persistent subscriptions",
@event.GetType().Name,
sequence);
}
}
}
}