Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 

149 рядки
5.5 KiB

  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using MQTTnet.Packets;
  6. using MQTTnet.Protocol;
  7. namespace MQTTnet.Server
  8. {
  9. public class MqttClientSubscriptionsManager
  10. {
  11. private readonly ConcurrentDictionary<string, MqttQualityOfServiceLevel> _subscriptions = new ConcurrentDictionary<string, MqttQualityOfServiceLevel>();
  12. private readonly IMqttServerOptions _options;
  13. private readonly MqttServer _server;
  14. private readonly string _clientId;
  15. public MqttClientSubscriptionsManager(string clientId, IMqttServerOptions options, MqttServer server)
  16. {
  17. _clientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
  18. _options = options ?? throw new ArgumentNullException(nameof(options));
  19. _server = server;
  20. }
  21. public MqttClientSubscribeResult Subscribe(MqttSubscribePacket subscribePacket)
  22. {
  23. if (subscribePacket == null) throw new ArgumentNullException(nameof(subscribePacket));
  24. var result = new MqttClientSubscribeResult
  25. {
  26. ResponsePacket = new MqttSubAckPacket
  27. {
  28. PacketIdentifier = subscribePacket.PacketIdentifier
  29. },
  30. CloseConnection = false
  31. };
  32. foreach (var topicFilter in subscribePacket.TopicFilters)
  33. {
  34. var interceptorContext = InterceptSubscribe(topicFilter);
  35. if (!interceptorContext.AcceptSubscription)
  36. {
  37. result.ResponsePacket.SubscribeReturnCodes.Add(MqttSubscribeReturnCode.Failure);
  38. }
  39. else
  40. {
  41. result.ResponsePacket.SubscribeReturnCodes.Add(ConvertToMaximumQoS(topicFilter.QualityOfServiceLevel));
  42. }
  43. if (interceptorContext.CloseConnection)
  44. {
  45. result.CloseConnection = true;
  46. }
  47. if (interceptorContext.AcceptSubscription)
  48. {
  49. _subscriptions[topicFilter.Topic] = topicFilter.QualityOfServiceLevel;
  50. _server.OnClientSubscribedTopic(_clientId, topicFilter);
  51. }
  52. }
  53. return result;
  54. }
  55. public MqttUnsubAckPacket Unsubscribe(MqttUnsubscribePacket unsubscribePacket)
  56. {
  57. if (unsubscribePacket == null) throw new ArgumentNullException(nameof(unsubscribePacket));
  58. foreach (var topicFilter in unsubscribePacket.TopicFilters)
  59. {
  60. _subscriptions.TryRemove(topicFilter, out _);
  61. _server.OnClientUnsubscribedTopic(_clientId, topicFilter);
  62. }
  63. return new MqttUnsubAckPacket
  64. {
  65. PacketIdentifier = unsubscribePacket.PacketIdentifier
  66. };
  67. }
  68. public CheckSubscriptionsResult CheckSubscriptions(MqttApplicationMessage applicationMessage)
  69. {
  70. if (applicationMessage == null) throw new ArgumentNullException(nameof(applicationMessage));
  71. var qosLevels = new HashSet<MqttQualityOfServiceLevel>();
  72. foreach (var subscription in _subscriptions)
  73. {
  74. if (!MqttTopicFilterComparer.IsMatch(applicationMessage.Topic, subscription.Key))
  75. {
  76. continue;
  77. }
  78. qosLevels.Add(subscription.Value);
  79. }
  80. if (qosLevels.Count == 0)
  81. {
  82. return new CheckSubscriptionsResult
  83. {
  84. IsSubscribed = false
  85. };
  86. }
  87. return CreateSubscriptionResult(applicationMessage, qosLevels);
  88. }
  89. private static MqttSubscribeReturnCode ConvertToMaximumQoS(MqttQualityOfServiceLevel qualityOfServiceLevel)
  90. {
  91. switch (qualityOfServiceLevel)
  92. {
  93. case MqttQualityOfServiceLevel.AtMostOnce: return MqttSubscribeReturnCode.SuccessMaximumQoS0;
  94. case MqttQualityOfServiceLevel.AtLeastOnce: return MqttSubscribeReturnCode.SuccessMaximumQoS1;
  95. case MqttQualityOfServiceLevel.ExactlyOnce: return MqttSubscribeReturnCode.SuccessMaximumQoS2;
  96. default: return MqttSubscribeReturnCode.Failure;
  97. }
  98. }
  99. private MqttSubscriptionInterceptorContext InterceptSubscribe(TopicFilter topicFilter)
  100. {
  101. var interceptorContext = new MqttSubscriptionInterceptorContext(_clientId, topicFilter);
  102. _options.SubscriptionInterceptor?.Invoke(interceptorContext);
  103. return interceptorContext;
  104. }
  105. private static CheckSubscriptionsResult CreateSubscriptionResult(MqttApplicationMessage applicationMessage, HashSet<MqttQualityOfServiceLevel> subscribedQoSLevels)
  106. {
  107. MqttQualityOfServiceLevel effectiveQoS;
  108. if (subscribedQoSLevels.Contains(applicationMessage.QualityOfServiceLevel))
  109. {
  110. effectiveQoS = applicationMessage.QualityOfServiceLevel;
  111. }
  112. else if (subscribedQoSLevels.Count == 1)
  113. {
  114. effectiveQoS = subscribedQoSLevels.First();
  115. }
  116. else
  117. {
  118. effectiveQoS = subscribedQoSLevels.Max();
  119. }
  120. return new CheckSubscriptionsResult
  121. {
  122. IsSubscribed = true,
  123. QualityOfServiceLevel = effectiveQoS
  124. };
  125. }
  126. }
  127. }