public static IEventObservable <TEvent, IEventContext, TModel> GetEventObservable <TEvent, TModel>(this IRouter <TModel> router, IEventHoldingStrategy <TEvent, TModel> strategy) where TEvent : IIdentifiableEvent where TModel : IHeldEventStore { return(EventObservable.Create <TEvent, IEventContext, TModel>( o => { var heldEvents = new Dictionary <Guid, HeldEventData <TEvent> >(); var releasedEvents = new HashSet <Guid>(); var disposables = new CollectionDisposable(); disposables.Add(router.GetEventObservable <TEvent>(ObservationStage.Preview).Observe((e, c, m) => { // Have we already re-published this event? If so we don't want to hold it again. if (releasedEvents.Contains(e.Id)) { releasedEvents.Remove(e.Id); o.OnNext(e, c, m); } else { var shouldHoldEvent = strategy.ShouldHold(e, c, m); if (shouldHoldEvent) { // Cancel the event so no other observers will receive it. c.Cancel(); // Model that we've cancelled it, other code can now reflect the newly modelled values. // That is other code needs to determine what to do with these held events on the model. // When it figures that out it should raise a HeldEventActionEvent so we can proceed here. IEventDescription eventDescription = strategy.GetEventDescription(e, m); m.AddHeldEventDescription(eventDescription); // finally we hold the event locally heldEvents.Add(e.Id, new HeldEventData <TEvent>(eventDescription, e)); } } })); disposables.Add(router.GetEventObservable <HeldEventActionEvent>().Observe((e, c, m) => { HeldEventData <TEvent> heldEventData; // Since we're listening to a pipe of all events we need to filter out anything we don't know about. if (heldEvents.TryGetValue(e.EventId, out heldEventData)) { // We're received an event to clean up. heldEvents.Remove(e.EventId); m.RemoveHeldEventDescription(heldEventData.EventDescription); if (e.Action == HeldEventAction.Release) { // Temporarily store the event we're republishing so we don't re-hold it releasedEvents.Add(e.EventId); router.PublishEvent(heldEventData.Event); } } })); return disposables; } )); }
private static IEventObservable <TEvent, TContext, TModel> MergeInternal <TEvent, TContext, TModel>(IEnumerable <IEventObservable <TEvent, TContext, TModel> > sources) { return(Create <TEvent, TContext, TModel>( o => { var disposables = new CollectionDisposable(); foreach (IEventObservable <TEvent, TContext, TModel> source in sources) { disposables.Add(source.Observe(o)); } return disposables; } )); }