public async Task <SubscribeResult> Subscribe(MqttSubscribePacket subscribePacket) { if (subscribePacket == null) { throw new ArgumentNullException(nameof(subscribePacket)); } var retainedApplicationMessages = await _retainedMessagesManager.GetMessagesAsync().ConfigureAwait(false); var result = new SubscribeResult(); // 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 interceptorContext = await InterceptSubscribe(originalTopicFilter).ConfigureAwait(false); var finalTopicFilter = interceptorContext?.TopicFilter ?? originalTopicFilter; var acceptSubscription = interceptorContext?.AcceptSubscription ?? true; var closeConnection = interceptorContext?.CloseConnection ?? false; if (string.IsNullOrEmpty(finalTopicFilter.Topic) || !acceptSubscription) { result.ReturnCodes.Add(MqttSubscribeReturnCode.Failure); result.ReasonCodes.Add(MqttSubscribeReasonCode.UnspecifiedError); } else { result.ReturnCodes.Add(ConvertToSubscribeReturnCode(finalTopicFilter.QualityOfServiceLevel)); result.ReasonCodes.Add(ConvertToSubscribeReasonCode(finalTopicFilter.QualityOfServiceLevel)); } if (closeConnection) { result.CloseConnection = true; } if (!acceptSubscription || string.IsNullOrEmpty(finalTopicFilter.Topic)) { continue; } var subscription = CreateSubscription(finalTopicFilter, subscribePacket); await _eventDispatcher.SafeNotifyClientSubscribedTopicAsync(_clientSession.ClientId, finalTopicFilter).ConfigureAwait(false); FilterRetainedApplicationMessages(retainedApplicationMessages, subscription, result); } return(result); }
static void FilterRetainedApplicationMessages(IList <MqttApplicationMessage> retainedApplicationMessages, Subscription subscription, SubscribeResult subscribeResult) { for (var i = retainedApplicationMessages.Count - 1; i >= 0; i--) { var retainedApplicationMessage = retainedApplicationMessages[i]; if (retainedApplicationMessage == null) { continue; } if (subscription.RetainHandling == MqttRetainHandling.DoNotSendOnSubscribe) { // This is a MQTT V5+ feature. continue; } if (subscription.RetainHandling == MqttRetainHandling.SendAtSubscribeIfNewSubscriptionOnly && !subscription.IsNewSubscription) { // This is a MQTT V5+ feature. continue; } if (!MqttTopicFilterComparer.IsMatch(retainedApplicationMessage.Topic, subscription.Topic)) { continue; } var queuedApplicationMessage = new MqttQueuedApplicationMessage { ApplicationMessage = retainedApplicationMessage, IsRetainedMessage = true, SubscriptionQualityOfServiceLevel = subscription.QualityOfServiceLevel }; if (subscription.Identifier > 0) { queuedApplicationMessage.SubscriptionIdentifiers = new List <uint> { subscription.Identifier }; } subscribeResult.RetainedApplicationMessages.Add(queuedApplicationMessage); retainedApplicationMessages[i] = null; } }