static void FilterRetainedApplicationMessages( IList <MqttApplicationMessage> retainedApplicationMessages, CreateSubscriptionResult createSubscriptionResult, SubscribeResult subscribeResult) { for (var index = retainedApplicationMessages.Count - 1; index >= 0; index--) { var retainedApplicationMessage = retainedApplicationMessages[index]; if (retainedApplicationMessage == null) { continue; } if (createSubscriptionResult.Subscription.RetainHandling == MqttRetainHandling.DoNotSendOnSubscribe) { // This is a MQTT V5+ feature. continue; } if (createSubscriptionResult.Subscription.RetainHandling == MqttRetainHandling.SendAtSubscribeIfNewSubscriptionOnly && !createSubscriptionResult.IsNewSubscription) { // This is a MQTT V5+ feature. continue; } if (MqttTopicFilterComparer.Compare(retainedApplicationMessage.Topic, createSubscriptionResult.Subscription.Topic) != MqttTopicFilterCompareResult.IsMatch) { continue; } var retainedMessageMatch = new MqttRetainedMessageMatch { ApplicationMessage = retainedApplicationMessage, SubscriptionQualityOfServiceLevel = createSubscriptionResult.Subscription.GrantedQualityOfServiceLevel }; if (subscribeResult.RetainedMessages == null) { subscribeResult.RetainedMessages = new List <MqttRetainedMessageMatch>(); } subscribeResult.RetainedMessages.Add(retainedMessageMatch); // Clear the retained message from the list because the client should receive every message only // one time even if multiple subscriptions affect them. retainedApplicationMessages[index] = null; } }
public async Task <SubscribeResult> Subscribe(MqttSubscribePacket subscribePacket, CancellationToken cancellationToken) { if (subscribePacket == null) { throw new ArgumentNullException(nameof(subscribePacket)); } var retainedApplicationMessages = await _retainedMessagesManager.GetMessages().ConfigureAwait(false); var result = new SubscribeResult { ReasonCodes = new List <MqttSubscribeReasonCode>(subscribePacket.TopicFilters.Count) }; var addedSubscriptions = new List <string>(); // The topic filters are order by its QoS so that the higher QoS will win over a // lower one. foreach (var originalTopicFilter in subscribePacket.TopicFilters.OrderByDescending(f => f.QualityOfServiceLevel)) { var subscriptionEventArgs = await InterceptSubscribe(originalTopicFilter, cancellationToken).ConfigureAwait(false); var finalTopicFilter = subscriptionEventArgs.TopicFilter; var processSubscription = subscriptionEventArgs.ProcessSubscription && subscriptionEventArgs.Response.ReasonCode <= MqttSubscribeReasonCode.GrantedQoS2; result.UserProperties = subscriptionEventArgs.UserProperties; result.ReasonString = subscriptionEventArgs.ReasonString; result.ReasonCodes.Add(subscriptionEventArgs.Response.ReasonCode); if (subscriptionEventArgs.CloseConnection) { // When any of the interceptor calls leads to a connection close the connection // must be closed. So do not revert to false! result.CloseConnection = true; } if (!processSubscription || string.IsNullOrEmpty(finalTopicFilter.Topic)) { continue; } var createSubscriptionResult = CreateSubscription(finalTopicFilter, subscribePacket.SubscriptionIdentifier, subscriptionEventArgs.Response.ReasonCode); addedSubscriptions.Add(finalTopicFilter.Topic); if (_eventContainer.ClientSubscribedTopicEvent.HasHandlers) { var eventArgs = new ClientSubscribedTopicEventArgs { ClientId = _session.Id, TopicFilter = finalTopicFilter }; await _eventContainer.ClientSubscribedTopicEvent.InvokeAsync(eventArgs).ConfigureAwait(false); } FilterRetainedApplicationMessages(retainedApplicationMessages, createSubscriptionResult, result); } _subscriptionChangedNotification?.OnSubscriptionsAdded(_session, addedSubscriptions); return(result); }