/// <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(); }
/// <summary> /// Constructor /// </summary> public MqttSubscriberManager() { this.subscribers = new Dictionary <string, List <MqttSubscription> >(); this.comparer = new MqttSubscriptionComparer(MqttSubscriptionComparer.MqttSubscriptionComparerType.OnClientId); }