Пример #1
0
        /// <summary>
        /// Add a subscriber for a topic
        /// </summary>
        /// <param name="topic">Topic for subscription</param>
        /// <param name="qosLevel">QoS level for the topic subscription</param>
        /// <param name="client">Client to subscribe</param>
        public void Subscribe(string topic, byte qosLevel, MqttClient client)
        {
            string topicReplaced = topic.Replace(PLUS_WILDCARD, PLUS_WILDCARD_REPLACE).Replace(SHARP_WILDCARD, SHARP_WILDCARD_REPLACE);

            lock (this.subscribers)
            {
                // if the topic doesn't exist
                if (!this.subscribers.ContainsKey(topicReplaced))
                {
                    // create a new empty subscription list for the topic
                    List <MqttSubscription> list = new List <MqttSubscription>();
                    this.subscribers.Add(topicReplaced, list);
                }

                // query for check client already subscribed
                var query = from s in this.subscribers[topicReplaced]
                            where s.ClientId == client.ClientId
                            select s;

                // if the client isn't already subscribed to the topic
                if (!query.Any())
                {
                    MqttSubscription subscription = new MqttSubscription()
                    {
                        ClientId = client.ClientId,
                        Topic    = topicReplaced,
                        QosLevel = qosLevel,
                        Client   = client
                    };
                    // add subscription to the list for the topic
                    this.subscribers[topicReplaced].Add(subscription);
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Remove a subscriber for a topic
        /// </summary>
        /// <param name="topic">Topic for unsubscription</param>
        /// <param name="client">Client to unsubscribe</param>
        public void Unsubscribe(string topic, MqttClient client)
        {
            string topicReplaced = topic.Replace(PLUS_WILDCARD, PLUS_WILDCARD_REPLACE).Replace(SHARP_WILDCARD, SHARP_WILDCARD_REPLACE);

            lock (this.subscribers)
            {
                // if the topic exists
                if (this.subscribers.ContainsKey(topicReplaced))
                {
                    // query for check client subscribed
                    var query = from s in this.subscribers[topicReplaced]
                                where s.ClientId == client.ClientId
                                select s;

                    // if the client is subscribed for the topic
                    if (query.Count() > 0)
                    {
                        MqttSubscription subscription = query.First();

                        // remove subscription from the list for the topic
                        this.subscribers[topicReplaced].Remove(subscription);
                        // dispose subscription
                        subscription.Dispose();

                        // remove topic if there aren't subscribers
                        if (this.subscribers[topicReplaced].Count == 0)
                        {
                            this.subscribers.Remove(topicReplaced);
                        }
                    }
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Publish retained message for a topic to a client
        /// </summary>
        /// <param name="topic">Topic to search for a retained message</param>
        /// <param name="clientId">Client Id to send retained message</param>
        public void PublishRetaind(string topic, string clientId)
        {
            lock (this.subscribersForRetained)
            {
                MqttSubscription subscription = this.subscriberManager.GetSubscription(topic, clientId);

                // add subscription to list of subscribers for receiving retained messages
                if (subscription != null)
                {
                    this.subscribersForRetained.Enqueue(subscription);
                }
            }

            // unlock thread for sending messages to the subscribers
            this.publishQueueWaitHandle.Set();
        }
Пример #4
0
        /// <summary>
        /// Remove a subscriber for all topics
        /// </summary>
        /// <param name="client">Client to unsubscribe</param>
        public void Unsubscribe(MqttClient client)
        {
            lock (this.subscribers)
            {
                List <string> topicToRemove = new List <string>();

                foreach (string topic in this.subscribers.Keys)
                {
                    // query for check client subscribed
                    var query = from s in this.subscribers[topic]
                                where s.ClientId == client.ClientId
                                select s;

                    // if the client is subscribed for the topic
                    if (query.Count() > 0)
                    {
                        MqttSubscription subscription = query.First();

                        // remove subscription from the list for the topic
                        this.subscribers[topic].Remove(subscription);
                        // dispose subscription
                        subscription.Dispose();

                        // add topic to remove list if there aren't subscribers
                        if (this.subscribers[topic].Count == 0)
                        {
                            topicToRemove.Add(topic);
                        }
                    }
                }

                // remove topic without subscribers
                // loop needed to avoid exception on modify collection inside previous loop
                foreach (string topic in topicToRemove)
                {
                    this.subscribers.Remove(topic);
                }
            }
        }
Пример #5
0
        /// <summary>
        /// Process the message queue to publish
        /// </summary>
        public void PublishThread()
        {
            int            count;
            byte           qosLevel;
            MqttMsgPublish publish;

            // create event to signal that current thread is ended
            this.publishEventEnd = new AutoResetEvent(false);

            while (this.isRunning)
            {
                // wait on message queueud to publish
                this.publishQueueWaitHandle.WaitOne();

                // first check new subscribers to send retained messages ...
                lock (this.subscribersForRetained)
                {
                    count = this.subscribersForRetained.Count;

                    // publish retained messages to subscribers (new or reconnected)
                    while (count > 0)
                    {
                        count--;
                        MqttSubscription subscription = this.subscribersForRetained.Dequeue();

                        var query = from p in this.retainedMessages
                                    where (new Regex(subscription.Topic)).IsMatch(p.Key)     // check for topics based also on wildcard with regex
                                    select p.Value;

                        if (query.Count() > 0)
                        {
                            // reverse loop to allow for changes in "this.retainedMessages"
                            for (int i = query.Count() - 1; i >= 0; i--)
                            {
                                MqttMsgPublish retained = query.ElementAt(i);

                                qosLevel = (subscription.QosLevel < retained.QosLevel) ? subscription.QosLevel : retained.QosLevel;

                                // send PUBLISH message to the current subscriber
                                subscription.Client.Publish(retained.Topic, retained.Message, qosLevel, retained.Retain);
                            }
                        }
                    }
                }

                // ... then check clients to send outgoing session messages
                lock (this.clientsForSession)
                {
                    count = this.clientsForSession.Count;

                    // publish outgoing session messages to clients (reconnected)
                    while (count > 0)
                    {
                        count--;
                        string clientId = this.clientsForSession.Dequeue();

                        MqttBrokerSession session = this.sessionManager.GetSession(clientId);

                        while (session.OutgoingMessages.Count > 0)
                        {
                            MqttMsgPublish outgoingMsg = session.OutgoingMessages.Dequeue();

                            var query = from s in session.Subscriptions
                                        where (new Regex(s.Topic)).IsMatch(outgoingMsg.Topic) // check for topics based also on wildcard with regex
                                        select s;

                            MqttSubscription subscription = query.First();

                            if (subscription != null)
                            {
                                qosLevel = (subscription.QosLevel < outgoingMsg.QosLevel) ? subscription.QosLevel : outgoingMsg.QosLevel;

                                session.Client.Publish(outgoingMsg.Topic, outgoingMsg.Message, qosLevel, outgoingMsg.Retain);
                            }
                        }
                    }
                }

                // ... then pass to process publish queue
                lock (this.publishQueue)
                {
                    publish = null;

                    count = this.publishQueue.Count;
                    // publish all queued messages
                    while (count > 0)
                    {
                        count--;
                        publish = (MqttMsgPublish)this.publishQueue.Dequeue();

                        if (publish != null)
                        {
                            // get all subscriptions for a topic
                            List <MqttSubscription> subscriptions = this.subscriberManager.GetSubscriptionsByTopic(publish.Topic);

                            if ((subscriptions != null) && (subscriptions.Count > 0))
                            {
                                foreach (MqttSubscription subscription in subscriptions)
                                {
                                    qosLevel = (subscription.QosLevel < publish.QosLevel) ? subscription.QosLevel : publish.QosLevel;

                                    // send PUBLISH message to the current subscriber
                                    subscription.Client.Publish(publish.Topic, publish.Message, qosLevel, publish.Retain);
                                }
                            }

                            // get all sessions
                            List <MqttBrokerSession> sessions = this.sessionManager.GetSessions();

                            if ((sessions != null) && (sessions.Count > 0))
                            {
                                foreach (MqttBrokerSession session in sessions)
                                {
                                    var query = from s in session.Subscriptions
                                                where (new Regex(s.Topic)).IsMatch(publish.Topic)
                                                select s;

                                    MqttSubscriptionComparer comparer = new MqttSubscriptionComparer(MqttSubscriptionComparer.MqttSubscriptionComparerType.OnClientId);

                                    // consider only session active for client disconnected (not online)
                                    if (session.Client == null)
                                    {
                                        foreach (MqttSubscription subscription in query.Distinct(comparer))
                                        {
                                            qosLevel = (subscription.QosLevel < publish.QosLevel) ? subscription.QosLevel : publish.QosLevel;

                                            // save PUBLISH message for client disconnected (not online)
                                            session.OutgoingMessages.Enqueue(publish);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // signal thread end
            this.publishEventEnd.Set();
        }