// Called by rendezvous when new remote subscriber subscribes to this stream.
        private void AddSubscriber_Impl(
            GuidId subscriptionId,
            StreamId streamId,
            IStreamConsumerExtension streamConsumer,
            StreamSequenceToken token,
            IStreamFilterPredicateWrapper filter)
        {
            StreamConsumerCollection streamDataCollection;

            if (!pubSubCache.TryGetValue(streamId, out streamDataCollection))
            {
                streamDataCollection = new StreamConsumerCollection();
                pubSubCache.Add(streamId, streamDataCollection);
            }

            StreamConsumerData data;

            if (!streamDataCollection.TryGetConsumer(subscriptionId, out data))
            {
                data = streamDataCollection.AddConsumer(subscriptionId, streamId, streamConsumer, token, filter);
            }

            // Set cursor if not cursor is set, or if subscription provides new token
            if (data.Cursor == null || token != null)
            {
                data.Cursor = this.receiver.GetCacheCursor(streamId.Guid, streamId.Namespace, token);
            }

            if (data.State == StreamConsumerDataState.Inactive)
            {
                RunConsumerCursor(data, filter).Ignore(); // Start delivering events if not actively doing so
            }
        }
        // Called by rendezvous when new remote subscriber subscribes to this stream.
        private async Task AddSubscriber_Impl(
            GuidId subscriptionId,
            StreamId streamId,
            IStreamConsumerExtension streamConsumer,
            StreamSequenceToken cacheToken,
            IStreamFilterPredicateWrapper filter)
        {
            if (IsShutdown)
            {
                return;
            }

            StreamConsumerCollection streamDataCollection;

            if (!pubSubCache.TryGetValue(streamId, out streamDataCollection))
            {
                streamDataCollection = new StreamConsumerCollection(DateTime.UtcNow);
                pubSubCache.Add(streamId, streamDataCollection);
            }

            StreamConsumerData data;

            if (!streamDataCollection.TryGetConsumer(subscriptionId, out data))
            {
                data = streamDataCollection.AddConsumer(subscriptionId, streamId, streamConsumer, filter ?? DefaultStreamFilter);
            }

            if (await DoHandshakeWithConsumer(data, cacheToken))
            {
                if (data.State == StreamConsumerDataState.Inactive)
                {
                    RunConsumerCursor(data, data.Filter).Ignore(); // Start delivering events if not actively doing so
                }
            }
        }
        private void RegisterStream(StreamId streamId, StreamSequenceToken firstToken)
        {
            var streamData = new StreamConsumerCollection();

            pubSubCache.Add(streamId, streamData);
            RegisterAsStreamProducer(streamId, firstToken).Ignore();
        }
 private void StartInactiveCursors(StreamConsumerCollection streamData, StreamSequenceToken startToken)
 {
     foreach (StreamConsumerData consumerData in streamData.AllConsumers())
     {
         consumerData.Cursor?.Refresh(startToken);
         if (consumerData.State == StreamConsumerDataState.Inactive)
         {
             // wake up inactive consumers
             RunConsumerCursor(consumerData, consumerData.Filter).Ignore();
         }
     }
 }
        private void StartInactiveCursors(StreamId streamId, StreamConsumerCollection streamData)
        {
            // if stream is already registered, just wake inactive consumers
            // get list of inactive consumers
            var streamConsumers = streamData.AllConsumersForStream(streamId)
                                  .Where(consumer => consumer.State == StreamConsumerDataState.Inactive)
                                  .ToList();

            // for each inactive stream
            foreach (StreamConsumerData consumerData in streamConsumers)
            {
                RunConsumerCursor(consumerData, consumerData.Filter).Ignore();
            }
        }
 private void StartInactiveCursors(StreamConsumerCollection streamData)
 {
     foreach (StreamConsumerData consumerData in streamData.AllConsumers())
     {
         if (consumerData.State == StreamConsumerDataState.Inactive)
         {
             // wake up inactive consumers
             RunConsumerCursor(consumerData, consumerData.Filter).Ignore();
         }
         else
         {
             if (consumerData.Cursor != null)
             {
                 consumerData.Cursor.Refresh();
             }
         }
     }
 }
        private async Task RegisterStream(StreamId streamId, StreamSequenceToken firstToken, DateTime now)
        {
            var streamData = new StreamConsumerCollection(now);
            pubSubCache.Add(streamId, streamData);
            // Create a fake cursor to point into a cache.
            // That way we will not purge the event from the cache, until we talk to pub sub.
            // This will help ensure the "casual consistency" between pre-existing subscripton (of a potentially new already subscribed consumer) 
            // and later production.
            var pinCursor = queueCache.GetCacheCursor(streamId, firstToken);

            try
            {
                await RegisterAsStreamProducer(streamId, firstToken);
            }finally
            {
                // Cleanup the fake pinning cursor.
                pinCursor.Dispose();
            }
        }
        // Called by rendezvous when new remote subscriber subscribes to this stream or when registering a new stream with the pubsub system.
        private void AddSubscriberToSubscriptionCache(
            GuidId subscriptionId,
            StreamId streamId,
            IStreamConsumerExtension streamConsumer,
            IQueueCacheCursor newCursor,
            StreamSequenceToken requestedToken,
            IStreamFilterPredicateWrapper filter)
        {
            StreamConsumerCollection streamDataCollection;

            if (!pubSubCache.TryGetValue(streamId, out streamDataCollection))
            {
                streamDataCollection = new StreamConsumerCollection(DateTime.UtcNow);
                pubSubCache.Add(streamId, streamDataCollection);
            }

            StreamConsumerData data;

            if (!streamDataCollection.TryGetConsumer(subscriptionId, out data))
            {
                data = streamDataCollection.AddConsumer(subscriptionId, streamId, streamConsumer, filter);
            }

            data.LastToken = requestedToken;

            // if we have a new cursor, use it
            if (newCursor != null)
            {
                data.Cursor = newCursor;
            } // else if we don't yet have a cursor, get a cursor at the end of the cash (null sequence token).
            else if (data.Cursor == null && queueCache != null)
            {
                data.Cursor = queueCache.GetCacheCursor(streamId.Guid, streamId.Namespace, null);
            }

            if (data.State == StreamConsumerDataState.Inactive)
            {
                RunConsumerCursor(data, filter).Ignore(); // Start delivering events if not actively doing so
            }
        }
 private void StartInactiveCursors(StreamConsumerCollection streamData)
 {
     foreach (StreamConsumerData consumerData in streamData.AllConsumers())
     {
         if (consumerData.State == StreamConsumerDataState.Inactive)
         {
             // wake up inactive consumers
             RunConsumerCursor(consumerData, consumerData.Filter).Ignore();
         }
         else
         {
             if (consumerData.Cursor != null)
             {
                 consumerData.Cursor.Refresh();
             }
         }
     }
 }
        private async Task RegisterStream(StreamId streamId, StreamSequenceToken firstToken, DateTime now)
        {
            var streamData = new StreamConsumerCollection(now);
            pubSubCache.Add(streamId, streamData);
            // Create a fake cursor to point into a cache.
            // That way we will not purge the event from the cache, until we talk to pub sub.
            // This will help ensure the "casual consistency" between pre-existing subscripton (of a potentially new already subscribed consumer) 
            // and later production.
            var pinCursor = queueCache.GetCacheCursor(streamId.Guid, streamId.Namespace, firstToken);

            try
            {
                await RegisterAsStreamProducer(streamId, firstToken);
            }finally
            {
                // Cleanup the fake pinning cursor.
                pinCursor.Dispose();
            }
        }
        // Called by rendezvous when new remote subscriber subscribes to this stream.
        private async Task AddSubscriber_Impl(
            GuidId subscriptionId,
            StreamId streamId,
            IStreamConsumerExtension streamConsumer,
            StreamSequenceToken cacheToken,
            IStreamFilterPredicateWrapper filter)
        {
            if (IsShutdown) return;

            StreamConsumerCollection streamDataCollection;
            if (!pubSubCache.TryGetValue(streamId, out streamDataCollection))
            {
                streamDataCollection = new StreamConsumerCollection(DateTime.UtcNow);
                pubSubCache.Add(streamId, streamDataCollection);
            }

            StreamConsumerData data;
            if (!streamDataCollection.TryGetConsumer(subscriptionId, out data))
                data = streamDataCollection.AddConsumer(subscriptionId, streamId, streamConsumer, filter ?? DefaultStreamFilter);

            if (await DoHandshakeWithConsumer(data, cacheToken))
            {
                if (data.State == StreamConsumerDataState.Inactive)
                    RunConsumerCursor(data, data.Filter).Ignore(); // Start delivering events if not actively doing so
            }
        }
        private void StartInactiveCursors(StreamId streamId, StreamConsumerCollection streamData)
        {
            // if stream is already registered, just wake inactive consumers
            // get list of inactive consumers
            var inactiveStreamConsumers = streamData.AllConsumers()
                .Where(consumer => consumer.State == StreamConsumerDataState.Inactive)
                .ToList();

            // for each inactive stream
            foreach (StreamConsumerData consumerData in inactiveStreamConsumers)
                RunConsumerCursor(consumerData, consumerData.Filter).Ignore();
        }
        // Called by rendezvous when new remote subscriber subscribes to this stream or when registering a new stream with the pubsub system.
        private void AddSubscriberToSubscriptionCache(
            GuidId subscriptionId,
            StreamId streamId,
            IStreamConsumerExtension streamConsumer,
            IQueueCacheCursor newCursor,
            StreamSequenceToken requestedToken,
            IStreamFilterPredicateWrapper filter)
        {
            StreamConsumerCollection streamDataCollection;
            if (!pubSubCache.TryGetValue(streamId, out streamDataCollection))
            {
                streamDataCollection = new StreamConsumerCollection(DateTime.UtcNow);
                pubSubCache.Add(streamId, streamDataCollection);
            }

            StreamConsumerData data;
            if (!streamDataCollection.TryGetConsumer(subscriptionId, out data))
                data = streamDataCollection.AddConsumer(subscriptionId, streamId, streamConsumer, filter);

            data.LastToken = requestedToken;

            // if we have a new cursor, use it
            if (newCursor != null)
            {
                data.Cursor = newCursor;
            } // else if we don't yet have a cursor, get a cursor at the end of the cash (null sequence token).
            else if (data.Cursor == null && queueCache != null)
            {
                data.Cursor = queueCache.GetCacheCursor(streamId.Guid, streamId.Namespace, null);
            }

            if (data.State == StreamConsumerDataState.Inactive)
                RunConsumerCursor(data, filter).Ignore(); // Start delivering events if not actively doing so
        }
        // Called by rendezvous when new remote subscriber subscribes to this stream.
        private void AddSubscriber_Impl(
            GuidId subscriptionId,
            StreamId streamId,
            IStreamConsumerExtension streamConsumer,
            StreamSequenceToken token,
            IStreamFilterPredicateWrapper filter)
        {
            StreamConsumerCollection streamDataCollection;
            if (!pubSubCache.TryGetValue(streamId, out streamDataCollection))
            {
                streamDataCollection = new StreamConsumerCollection();
                pubSubCache.Add(streamId, streamDataCollection);
            }

            StreamConsumerData data;
            if (!streamDataCollection.TryGetConsumer(subscriptionId, out data))
                data = streamDataCollection.AddConsumer(subscriptionId, streamId, streamConsumer, token, filter);
            
            // Set cursor if not cursor is set, or if subscription provides new token
            if ((data.Cursor == null || token != null) && queueCache != null)
                data.Cursor = queueCache.GetCacheCursor(streamId.Guid, streamId.Namespace, token);
            
            if (data.State == StreamConsumerDataState.Inactive)
                RunConsumerCursor(data, filter).Ignore(); // Start delivering events if not actively doing so
        }