void AddToLookup(Subscriber subscriber, MessageType typeName, string messageId)
        {
            try
            {
                // note: ReaderWriterLockSlim has a thread affinity and cannot be used with await!
                rwLock.EnterWriteLock();

                if (!lookup.TryGetValue(subscriber, out var dictionary))
                {
                    dictionary = new Dictionary <MessageType, string>();
                }
                else
                {
                    // replace existing subscriber
                    lookup.Remove(subscriber);
                }

                dictionary[typeName] = messageId;
                lookup[subscriber]   = dictionary;
            }
            finally
            {
                rwLock.ExitWriteLock();
            }
        }
        Dictionary <Subscriber, Dictionary <MessageType, string> > CreateLookup()
        {
            var output = new Dictionary <Subscriber, Dictionary <MessageType, string> >(SubscriberComparer);

            var messages = storageQueue.GetAllMessages()
                           .OrderByDescending(m => m.ArrivedTime)
                           .ThenBy(x => x.Id) // ensure same order of messages with same timestamp across all endpoints
                           .ToArray();

            foreach (var m in messages)
            {
                var messageTypeString = m.Body as string;
                var messageType       = new MessageType(messageTypeString); //this will parse both 2.6 and 3.0 type strings
                var subscriber        = Deserialize(m.Label);

                if (!output.TryGetValue(subscriber, out var endpointSubscriptions))
                {
                    output[subscriber] = endpointSubscriptions = new Dictionary <MessageType, string>();
                }

                if (endpointSubscriptions.ContainsKey(messageType))
                {
                    // this message is stale and can be removed
                    storageQueue.TryReceiveById(m.Id);
                }
                else
                {
                    endpointSubscriptions[messageType] = m.Id;
                }
            }

            return(output);
        }
예제 #3
0
        void ISubscriptionStorage.Init()
        {
            var path = MsmqUtilities.GetFullPath(Queue);

            q = new MessageQueue(path);

            bool transactional;
            try
            {
                transactional = q.Transactional;
            }
            catch (Exception ex)
            {
                throw new ArgumentException(string.Format("There is a problem with the subscription storage queue {0}. See enclosed exception for details.", Queue), ex);
            }

            if (!transactional && TransactionsEnabled)
                throw new ArgumentException("Queue must be transactional (" + Queue + ").");

            var messageReadPropertyFilter = new MessagePropertyFilter { Id = true, Body = true, Label = true };

            q.Formatter = new XmlMessageFormatter(new[] { typeof(string) });

            q.MessageReadPropertyFilter = messageReadPropertyFilter;

            foreach (var m in q.GetAllMessages())
            {
                var subscriber = Address.Parse(m.Label);
                var messageTypeString = m.Body as string;
                var messageType = new MessageType(messageTypeString); //this will parse both 2.6 and 3.0 type strings

                entries.Add(new Entry { MessageType = messageType, Subscriber = subscriber });
                AddToLookup(subscriber, messageType, m.Id);
            }
        }
        string RemoveFromLookup(Subscriber subscriber, MessageType typeName)
        {
            try
            {
                // note: ReaderWriterLockSlim has a thread affinity and cannot be used with await!
                rwLock.EnterWriteLock();

                if (lookup.TryGetValue(subscriber, out var subscriptions))
                {
                    if (subscriptions.TryGetValue(typeName, out var messageId))
                    {
                        subscriptions.Remove(typeName);
                        if (subscriptions.Count == 0)
                        {
                            lookup.Remove(subscriber);
                        }

                        return(messageId);
                    }
                }
            }
            finally
            {
                rwLock.ExitWriteLock();
            }

            return(null);
        }
        /// <summary>
        /// Adds a message to the subscription store.
        /// </summary>
        public void Add(Address subscriber, MessageType messageType)
        {
            var toSend = new Message {Formatter = q.Formatter, Recoverable = true, Label = subscriber.ToString(), Body = messageType.TypeName +  ", Version=" + messageType.Version};

            q.Send(toSend, GetTransactionType());

            AddToLookup(subscriber, messageType, toSend.Id);
        }
        /// <summary>
        /// Adds a message to the subscription store.
        /// </summary>
        public void Add(Address subscriber, MessageType messageType)
        {
            var toSend = new Message {
                Formatter = q.Formatter, Recoverable = true, Label = subscriber.ToString(), Body = messageType.TypeName + ", Version=" + messageType.Version
            };

            q.Send(toSend, GetTransactionType());

            AddToLookup(subscriber, messageType, toSend.Id);
        }
        /// <summary>
        /// Removes a message from the subscription store.
        /// </summary>
        public void Remove(Address subscriber, MessageType messageType)
        {
            var messageId = RemoveFromLookup(subscriber, messageType);

            if (messageId == null)
            {
                return;
            }

            q.ReceiveById(messageId, GetTransactionType());
        }
        public async Task Subscribers_are_deduplicated_based_on_transport_address_comparison_case_invariant()
        {
            var queue = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var messageType = new MessageType(typeof(SomeMessage));
            await storage.Subscribe(new Subscriber("sub1", null), messageType, new ContextBag());
            await storage.Subscribe(new Subscriber("SUB1", null), messageType, new ContextBag());

            var subscribers = await storage.GetSubscriberAddressesForMessage(new[] { messageType }, new ContextBag());
            Assert.AreEqual(1, subscribers.Count());
        }
        public Task Subscribe(Subscriber subscriber, MessageType messageType, ContextBag context)
        {
            var body      = $"{messageType.TypeName}, Version={messageType.Version}";
            var label     = Serialize(subscriber);
            var messageId = storageQueue.Send(body, label);

            AddToLookup(subscriber, messageType, messageId);

            log.DebugFormat($"Subscriber {subscriber.TransportAddress} added for message {messageType}.");

            return(TaskEx.CompletedTask);
        }
        public Task Unsubscribe(Subscriber subscriber, MessageType messageType, ContextBag context)
        {
            var messageId = RemoveFromLookup(subscriber, messageType);

            if (messageId != null)
            {
                storageQueue.TryReceiveById(messageId);
            }

            log.Debug($"Subscriber {subscriber.TransportAddress} removed for message {messageType}.");

            return(TaskEx.CompletedTask);
        }
예제 #11
0
        public async Task Can_have_multiple_subscribers_to_same_event_type()
        {
            var queue   = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var messageType = new MessageType(typeof(SomeMessage));
            await storage.Subscribe(new Subscriber("sub1", null), messageType, new ContextBag());

            await storage.Subscribe(new Subscriber("sub2", null), messageType, new ContextBag());

            var subscribers = await storage.GetSubscriberAddressesForMessage(new[] { messageType }, new ContextBag());

            Assert.AreEqual(2, subscribers.Count());
        }
예제 #12
0
        public async Task Subscribers_are_deduplicated_based_on_transport_address_comparison_case_invariant()
        {
            var queue   = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var messageType = new MessageType(typeof(SomeMessage));
            await storage.Subscribe(new Subscriber("sub1", null), messageType, new ContextBag());

            await storage.Subscribe(new Subscriber("SUB1", null), messageType, new ContextBag());

            var subscribers = await storage.GetSubscriberAddressesForMessage(new[] { messageType }, new ContextBag());

            Assert.AreEqual(1, subscribers.Count());
        }
예제 #13
0
        /// <summary>
        /// Adds a message to the lookup to find message from
        /// subscriber, to message type, to message id
        /// </summary>
        private void AddToLookup(Address subscriber, MessageType typeName, string messageId)
        {
            lock (lookup)
            {
                if (!lookup.ContainsKey(subscriber))
                {
                    lookup.Add(subscriber, new Dictionary <MessageType, string>());
                }

                if (!lookup[subscriber].ContainsKey(typeName))
                {
                    lookup[subscriber].Add(typeName, messageId);
                }
            }
        }
예제 #14
0
        /// <summary>
        /// Adds a message to the lookup to find message from
        /// subscriber, to message type, to message id
        /// </summary>
        private void AddToLookup(Address subscriber, MessageType typeName, string messageId)
        {
            lock (lookup)
            {
                Dictionary <MessageType, string> dictionary;
                if (!lookup.TryGetValue(subscriber, out dictionary))
                {
                    lookup[subscriber] = dictionary = new Dictionary <MessageType, string>();
                }

                if (!dictionary.ContainsKey(typeName))
                {
                    dictionary.Add(typeName, messageId);
                }
            }
        }
        public async Task Unsubscribe_is_persistent()
        {
            var queue = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var messageType = new MessageType(typeof(SomeMessage));
            await storage.Subscribe(new Subscriber("sub1", null), messageType, new ContextBag());
            storage = CreateAndInit(queue);

            await storage.Unsubscribe(new Subscriber("sub1", "endpointA"), messageType, new ContextBag());
            Assert.That(queue.GetAllMessages(), Is.Empty);

            storage = CreateAndInit(queue);
            var subscribers = await storage.GetSubscriberAddressesForMessage(new[] { messageType }, new ContextBag());
            Assert.AreEqual(0, subscribers.Count());
        }
예제 #16
0
        public async Task Can_handle_legacy_and_new_format()
        {
            var queue   = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var messageType  = new MessageType(typeof(SomeMessage));
            var messageTypes = new[] { messageType };
            await storage.Subscribe(new Subscriber("legacy", null), messageType, new ContextBag());

            await storage.Subscribe(new Subscriber("new", "endpoint"), messageType, new ContextBag());

            var subscribers = (await storage.GetSubscriberAddressesForMessage(messageTypes, new ContextBag())).ToArray();

            Assert.AreEqual(2, subscribers.Length);
            Assert.IsTrue(subscribers.Any(s => s.TransportAddress == "legacy" && s.Endpoint == null));
            Assert.IsTrue(subscribers.Any(s => s.TransportAddress == "new" && s.Endpoint == "endpoint"));
        }
        public async Task Subscribe_is_persistent()
        {
            var queue = new FakeStorageQueue();
            var messageType = new MessageType(typeof(SomeMessage));
            var storage = CreateAndInit(queue);

            await storage.Subscribe(new Subscriber("sub1", null), messageType, new ContextBag());
            await storage.Subscribe(new Subscriber("sub2", "endpointA"), messageType, new ContextBag());

            var storedMessages = queue.GetAllMessages().ToArray();
            Assert.That(storedMessages.Length, Is.EqualTo(2));

            storage = CreateAndInit(queue);
            var subscribers = (await storage.GetSubscriberAddressesForMessage(new[] { messageType }, new ContextBag())).ToArray();
            Assert.That(subscribers, Has.Exactly(1).Matches<Subscriber>(s => s.TransportAddress == "sub1" && s.Endpoint == null));
            Assert.That(subscribers, Has.Exactly(1).Matches<Subscriber>(s => s.TransportAddress == "sub2" && s.Endpoint == "endpointA"));
        }
예제 #18
0
        public async Task Unsubscribing_removes_all_subscriptions_with_same_address_but_different_endpoint_names()
        {
            var queue   = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var messageType  = new MessageType(typeof(SomeMessage));
            var messageTypes = new[] { messageType };
            await storage.Subscribe(new Subscriber("sub1", "e1"), messageType, new ContextBag());

            await storage.Subscribe(new Subscriber("sub1", "e2"), messageType, new ContextBag());

            await storage.Unsubscribe(new Subscriber("sub1", "e3"), messageType, new ContextBag());

            var subscribers = await storage.GetSubscriberAddressesForMessage(messageTypes, new ContextBag());

            Assert.AreEqual(0, subscribers.Count());
        }
예제 #19
0
        public async Task Two_subscribers_with_same_address_but_different_endpoint_are_considered_duplicates()
        {
            var queue   = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var messageType  = new MessageType(typeof(SomeMessage));
            var messageTypes = new[] { messageType };
            await storage.Subscribe(new Subscriber("sub1", null), messageType, new ContextBag());

            await storage.Subscribe(new Subscriber("sub1", "endpoint"), messageType, new ContextBag());

            var subscribers = await storage.GetSubscriberAddressesForMessage(messageTypes, new ContextBag());

            var subscriber = subscribers.Single();

            Assert.AreEqual("sub1", subscriber.TransportAddress);
            Assert.AreEqual("endpoint", subscriber.Endpoint);
        }
        public async Task Remove_outdated_subscriptions_on_initialization()
        {
            var queue = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var messageType = new MessageType(typeof(SomeMessage));
            await storage.Subscribe(new Subscriber("sub1", "1"), messageType, new ContextBag());
            await storage.Subscribe(new Subscriber("sub1", "2"), messageType, new ContextBag());
            await storage.Subscribe(new Subscriber("sub1", "3"), messageType, new ContextBag());

            storage = CreateAndInit(queue);
            var subscribers = (await storage.GetSubscriberAddressesForMessage(new[] { messageType }, new ContextBag())).ToArray();

            Assert.That(subscribers.Length, Is.EqualTo(1));
            Assert.That(subscribers[0].TransportAddress, Is.EqualTo("sub1"));
            Assert.That(subscribers[0].Endpoint, Is.EqualTo("3"));
            Assert.That(queue.GetAllMessages().Count(), Is.EqualTo(1));
        }
예제 #21
0
        public async Task Can_subscribe_to_multiple_events()
        {
            var queue   = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var someMessageType  = new MessageType(typeof(SomeMessage));
            var otherMessageType = new MessageType(typeof(OtherMessage));
            await storage.Subscribe(new Subscriber("sub1", null), someMessageType, new ContextBag());

            await storage.Subscribe(new Subscriber("sub1", null), otherMessageType, new ContextBag());

            var subscribers = await storage.GetSubscriberAddressesForMessage(new[] { someMessageType }, new ContextBag());

            Assert.AreEqual(1, subscribers.Count());

            subscribers = await storage.GetSubscriberAddressesForMessage(new[] { otherMessageType }, new ContextBag());

            Assert.AreEqual(1, subscribers.Count());
        }
예제 #22
0
        public async Task Unsubscribe_is_persistent()
        {
            var queue   = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var messageType = new MessageType(typeof(SomeMessage));
            await storage.Subscribe(new Subscriber("sub1", null), messageType, new ContextBag());

            storage = CreateAndInit(queue);

            await storage.Unsubscribe(new Subscriber("sub1", "endpointA"), messageType, new ContextBag());

            Assert.That(queue.GetAllMessages(), Is.Empty);

            storage = CreateAndInit(queue);
            var subscribers = await storage.GetSubscriberAddressesForMessage(new[] { messageType }, new ContextBag());

            Assert.AreEqual(0, subscribers.Count());
        }
예제 #23
0
        public async Task Same_subscriber_for_multiple_message_types_is_returned_only_once()
        {
            var queue   = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var someMessageType  = new MessageType(typeof(SomeMessage));
            var otherMessageType = new MessageType(typeof(OtherMessage));
            await storage.Subscribe(new Subscriber("sub1", null), someMessageType, new ContextBag());

            await storage.Subscribe(new Subscriber("sub1", null), otherMessageType, new ContextBag());

            var subscribers = await storage.GetSubscriberAddressesForMessage(new[]
            {
                someMessageType,
                otherMessageType
            }, new ContextBag());

            Assert.AreEqual(1, subscribers.Count());
        }
예제 #24
0
        void ISubscriptionStorage.Init()
        {
            var path = MsmqUtilities.GetFullPath(Queue);

            q = new MessageQueue(path);

            bool transactional;

            try
            {
                transactional = q.Transactional;
            }
            catch (Exception ex)
            {
                throw new ArgumentException(string.Format("There is a problem with the subscription storage queue {0}. See enclosed exception for details.", Queue), ex);
            }

            if (!transactional && SettingsHolder.Get <bool>("Transactions.Enabled"))
            {
                throw new ArgumentException("Queue must be transactional (" + Queue + ").");
            }

            var messageReadPropertyFilter = new MessagePropertyFilter {
                Id = true, Body = true, Label = true
            };

            q.Formatter = new XmlMessageFormatter(new[] { typeof(string) });

            q.MessageReadPropertyFilter = messageReadPropertyFilter;

            foreach (var m in q.GetAllMessages())
            {
                var subscriber        = Address.Parse(m.Label);
                var messageTypeString = m.Body as string;
                var messageType       = new MessageType(messageTypeString); //this will parse both 2.6 and 3.0 type strings

                entries.Add(new Entry {
                    MessageType = messageType, Subscriber = subscriber
                });
                AddToLookup(subscriber, messageType, m.Id);
            }
        }
예제 #25
0
        public async Task Subscribe_is_persistent()
        {
            var queue       = new FakeStorageQueue();
            var messageType = new MessageType(typeof(SomeMessage));
            var storage     = CreateAndInit(queue);

            await storage.Subscribe(new Subscriber("sub1", null), messageType, new ContextBag());

            await storage.Subscribe(new Subscriber("sub2", "endpointA"), messageType, new ContextBag());

            var storedMessages = queue.GetAllMessages().ToArray();

            Assert.That(storedMessages.Length, Is.EqualTo(2));

            storage = CreateAndInit(queue);
            var subscribers = (await storage.GetSubscriberAddressesForMessage(new[] { messageType }, new ContextBag())).ToArray();

            Assert.That(subscribers, Has.Exactly(1).Matches <Subscriber>(s => s.TransportAddress == "sub1" && s.Endpoint == null));
            Assert.That(subscribers, Has.Exactly(1).Matches <Subscriber>(s => s.TransportAddress == "sub2" && s.Endpoint == "endpointA"));
        }
예제 #26
0
        public async Task Remove_outdated_subscriptions_on_initialization()
        {
            var queue   = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var messageType = new MessageType(typeof(SomeMessage));
            await storage.Subscribe(new Subscriber("sub1", "1"), messageType, new ContextBag());

            await storage.Subscribe(new Subscriber("sub1", "2"), messageType, new ContextBag());

            await storage.Subscribe(new Subscriber("sub1", "3"), messageType, new ContextBag());

            storage = CreateAndInit(queue);
            var subscribers = (await storage.GetSubscriberAddressesForMessage(new[] { messageType }, new ContextBag())).ToArray();

            Assert.That(subscribers.Length, Is.EqualTo(1));
            Assert.That(subscribers[0].TransportAddress, Is.EqualTo("sub1"));
            Assert.That(subscribers[0].Endpoint, Is.EqualTo("3"));
            Assert.That(queue.GetAllMessages().Count(), Is.EqualTo(1));
        }
예제 #27
0
        string RemoveFromLookup(Address subscriber, MessageType typeName)
        {
            string messageId = null;

            lock (lookup)
            {
                Dictionary <MessageType, string> endpoints;
                if (lookup.TryGetValue(subscriber, out endpoints))
                {
                    if (endpoints.TryGetValue(typeName, out messageId))
                    {
                        endpoints.Remove(typeName);
                        if (endpoints.Count == 0)
                        {
                            lookup.Remove(subscriber);
                        }
                    }
                }
            }
            return(messageId);
        }
        public void Init()
        {
            var messages = storageQueue.GetAllMessages()
                           .OrderByDescending(m => m.ArrivedTime)
                           .ThenBy(x => x.Id) // ensure same order of messages with same timestamp across all endpoints
                           .ToArray();

            try
            {
                rwLock.EnterWriteLock();

                foreach (var m in messages)
                {
                    var messageTypeString = m.Body as string;
                    var messageType       = new MessageType(messageTypeString); //this will parse both 2.6 and 3.0 type strings
                    var subscriber        = Deserialize(m.Label);

                    if (!lookup.TryGetValue(subscriber, out var endpointSubscriptions))
                    {
                        lookup[subscriber] = endpointSubscriptions = new Dictionary <MessageType, string>();
                    }

                    if (endpointSubscriptions.ContainsKey(messageType))
                    {
                        // this message is stale and can be removed
                        storageQueue.TryReceiveById(m.Id);
                    }
                    else
                    {
                        endpointSubscriptions[messageType] = m.Id;
                    }
                }
            }
            finally
            {
                rwLock.ExitWriteLock();
            }
        }
        public async Task Can_subscribe_to_multiple_events()
        {
            var queue = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var someMessageType = new MessageType(typeof(SomeMessage));
            var otherMessageType = new MessageType(typeof(OtherMessage));
            await storage.Subscribe(new Subscriber("sub1", null), someMessageType, new ContextBag());
            await storage.Subscribe(new Subscriber("sub1", null), otherMessageType, new ContextBag());

            var subscribers = await storage.GetSubscriberAddressesForMessage(new[] { someMessageType }, new ContextBag());
            Assert.AreEqual(1, subscribers.Count());

            subscribers = await storage.GetSubscriberAddressesForMessage(new[] { otherMessageType }, new ContextBag());
            Assert.AreEqual(1, subscribers.Count());
        }
        public async Task Two_subscribers_with_same_address_but_different_endpoint_are_considered_duplicates()
        {
            var queue = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var messageType = new MessageType(typeof(SomeMessage));
            var messageTypes = new[] { messageType };
            await storage.Subscribe(new Subscriber("sub1", null), messageType, new ContextBag());
            await storage.Subscribe(new Subscriber("sub1", "endpoint"), messageType, new ContextBag());

            var subscribers = await storage.GetSubscriberAddressesForMessage(messageTypes, new ContextBag());

            var subscriber = subscribers.Single();
            Assert.AreEqual("sub1", subscriber.TransportAddress);
            Assert.AreEqual("endpoint", subscriber.Endpoint);
        }
        public async Task Unsubscribing_removes_all_subscriptions_with_same_address_but_different_endpoint_names()
        {
            var queue = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var messageType = new MessageType(typeof(SomeMessage));
            var messageTypes = new[] { messageType };
            await storage.Subscribe(new Subscriber("sub1", "e1"), messageType, new ContextBag());
            await storage.Subscribe(new Subscriber("sub1", "e2"), messageType, new ContextBag());

            await storage.Unsubscribe(new Subscriber("sub1", "e3"), messageType, new ContextBag());

            var subscribers = await storage.GetSubscriberAddressesForMessage(messageTypes, new ContextBag());
            Assert.AreEqual(0, subscribers.Count());
        }
        public async Task Can_have_multiple_subscribers_to_same_event_type()
        {
            var queue = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var messageType = new MessageType(typeof(SomeMessage));
            await storage.Subscribe(new Subscriber("sub1", null), messageType, new ContextBag());
            await storage.Subscribe(new Subscriber("sub2", null), messageType, new ContextBag());

            var subscribers = await storage.GetSubscriberAddressesForMessage(new[] { messageType }, new ContextBag());
            Assert.AreEqual(2, subscribers.Count());
        }
        /// <summary>
        /// Adds a message to the lookup to find message from
        /// subscriber, to message type, to message id
        /// </summary>
        private void AddToLookup(Address subscriber, MessageType typeName, string messageId)
        {
            lock (lookup)
            {
                if (!lookup.ContainsKey(subscriber))
                    lookup.Add(subscriber, new Dictionary<MessageType, string>());

                if (!lookup[subscriber].ContainsKey(typeName))
                    lookup[subscriber].Add(typeName, messageId);
            }
        }
예제 #34
0
        /// <summary>
        /// Removes a message from the subscription store.
        /// </summary>
        public void Remove(Address subscriber, MessageType messageType)
        {
            var messageId = RemoveFromLookup(subscriber, messageType);

            if (messageId == null)
                return;

            q.ReceiveById(messageId, GetTransactionType());
        }
예제 #35
0
        /// <summary>
        /// Adds a message to the lookup to find message from
        /// subscriber, to message type, to message id
        /// </summary>
        private void AddToLookup(Address subscriber, MessageType typeName, string messageId)
        {
            lock (lookup)
            {
                Dictionary<MessageType, string> dictionary;
                if (!lookup.TryGetValue(subscriber, out dictionary))
                {
                    lookup[subscriber] = dictionary = new Dictionary<MessageType, string>();
                }

                if (!dictionary.ContainsKey(typeName))
                {
                    dictionary.Add(typeName, messageId);
                }
            }
        }
예제 #36
0
 string RemoveFromLookup(Address subscriber, MessageType typeName)
 {
     string messageId = null;
     lock (lookup)
     {
         Dictionary<MessageType, string> endpoints;
         if (lookup.TryGetValue(subscriber, out endpoints))
         {
             if (endpoints.TryGetValue(typeName, out messageId))
             {
                 endpoints.Remove(typeName);
                 if (endpoints.Count == 0)
                 {
                     lookup.Remove(subscriber);
                 }
             }
         }
     }
     return messageId;
 }
        public async Task Can_handle_legacy_and_new_format()
        {
            var queue = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var messageType = new MessageType(typeof(SomeMessage));
            var messageTypes = new[] { messageType };
            await storage.Subscribe(new Subscriber("legacy", null), messageType, new ContextBag());
            await storage.Subscribe(new Subscriber("new", "endpoint"), messageType, new ContextBag());

            var subscribers = (await storage.GetSubscriberAddressesForMessage(messageTypes, new ContextBag())).ToArray();

            Assert.AreEqual(2, subscribers.Length);
            Assert.IsTrue(subscribers.Any(s => s.TransportAddress == "legacy" && s.Endpoint == null));
            Assert.IsTrue(subscribers.Any(s => s.TransportAddress == "new" && s.Endpoint == "endpoint"));
        }
        public async Task Same_subscriber_for_multiple_message_types_is_returned_only_once()
        {
            var queue = new FakeStorageQueue();
            var storage = CreateAndInit(queue);

            var someMessageType = new MessageType(typeof(SomeMessage));
            var otherMessageType = new MessageType(typeof(OtherMessage));
            await storage.Subscribe(new Subscriber("sub1", null), someMessageType, new ContextBag());
            await storage.Subscribe(new Subscriber("sub1", null), otherMessageType, new ContextBag());

            var subscribers = await storage.GetSubscriberAddressesForMessage(new[]
            {
                someMessageType,
                otherMessageType
            }, new ContextBag());

            Assert.AreEqual(1, subscribers.Count());
        }