/// <summary>
 /// Sets the Qos level of the last topic added to the subscription list via a call to ToTopic(string)
 /// </summary>
 /// <param name="qos">The Qos to set the last topic subscription to.</param>
 /// <returns>An update instance of the message.</returns>
 public MqttSubscribeMessage AtQos(MqttQos qos)
 {
     if (this.Payload.Subscriptions.ContainsKey(lastTopic))
     {
         this.Payload.Subscriptions[lastTopic] = qos;
     }
     return this;
 }
        public static short Publish(string topic, MqttQos qos, byte[] data)
        {
            if (mqttClient == null)
            {
                throw new InvalidOperationException("You must call Connect() on the MqttClientManager before attempting to publish");
            }

            return mqttClient.PublishMessage(topic, qos, data);
        }
        public void SubscriptionRequestCreatesPendingSubscription()
        {
            var chMock  = new Mock <IMqttConnectionHandler>();
            var pubMock = new Mock <IPublishingManager>();

            const string  topic = "testtopic";
            const MqttQos qos   = MqttQos.AtMostOnce;

            // run and verify the mocks were called.
            var subs = new Nmqtt.SubscriptionsManager(chMock.Object, pubMock.Object);

            subs.RegisterSubscription <string, AsciiPayloadConverter>(topic, qos);

            Assert.Equal(SubscriptionStatus.Pending, subs.GetSubscriptionsStatus(topic));
        }
Exemple #4
0
        /// <summary>
        /// 发布消息
        /// </summary>
        /// <param name="topic">主题</param>
        /// <param name="payload">有效载荷</param>
        /// <param name="qos">服务质量等级</param>
        public Task PublishAsync(string topic, byte[] payload, MqttQos qos = MqttQos.AtMostOnce)
        {
            var packet = new PublishPacket(qos)
            {
                TopicName = topic,
                Payload   = payload
            };

            if (qos > MqttQos.AtMostOnce)
            {
                packet.PacketId = _packetIdentifierProvider.GetNewPacketId();
            }

            return(_clientChannel.WriteAndFlushAsync(packet));
        }
Exemple #5
0
        /// <summary>
        /// 发布消息
        /// </summary>
        /// <param name="topic">主题</param>
        /// <param name="payload">有效载荷</param>
        /// <param name="qos">服务质量等级</param>
        /// <param name="retain"></param>
        public Task PublishAsync(string topic, byte[] payload, MqttQos qos = MqttQos.AtMostOnce, bool retain = false, CancellationToken cancellationToken = default)
        {
            var packet = new PublishPacket(qos, false, retain)
            {
                TopicName = topic,
                Payload   = payload
            };

            if (qos > MqttQos.AtMostOnce)
            {
                packet.PacketId = _packetIdProvider.NewPacketId();
            }

            return(SendAndFlushPacketAsync(packet));
        }
Exemple #6
0
 void AddRetainedRecursive(string topic, RetainedNode node, MqttQos qos, List <Tuple <string, MqttQos, byte[]> > result)
 {
     if (node.children == null)
     {
         return;
     }
     foreach (var child in node.children)
     {
         string childTopic = topic + "/" + child.Key;
         if (child.Value.body != null)
         {
             result.Add(new Tuple <string, MqttQos, byte[]>(childTopic, qos, child.Value.body));
         }
         AddRetainedRecursive(childTopic, child.Value, qos, result);
     }
 }
Exemple #7
0
        /// <summary>
        /// Creates a payload from the specified header stream.
        /// </summary>
        /// <param name="payloadStream"></param>
        public override void ReadFrom(Stream payloadStream)
        {
            int payloadBytesRead = 0;
            int payloadLength    = header.MessageSize - variableHeader.Length;

            // read all the topics and qos subscriptions from the message payload
            while (payloadBytesRead < payloadLength)
            {
                string  topic = payloadStream.ReadMqttString();
                MqttQos qos   = (MqttQos)payloadStream.ReadByte();

                payloadBytesRead += topic.Length + 3; // +3 = Mqtt string length bytes + qos byte

                AddSubscription(topic, qos);
            }
        }
        public void MultipleSubscriptionsForSamePendingThrowsException()
        {
            var chMock = new Mock <IMqttConnectionHandler>();

            // mock the call to register and save the callback for later.
            chMock.Setup((x) => x.RegisterForMessage(MqttMessageType.SubscribeAck, It.IsAny <Func <MqttMessage, bool> >()));

            string  topic = "testtopic";
            MqttQos qos   = MqttQos.AtMostOnce;

            // run and verify the mocks were called.
            Nmqtt.SubscriptionsManager subs = new Nmqtt.SubscriptionsManager(chMock.Object);
            subs.RegisterSubscription <AsciiPublishDataConverter>(topic, qos);
            chMock.VerifyAll();

            Assert.Throws <ArgumentException>(() => subs.RegisterSubscription <AsciiPublishDataConverter>(topic, qos));
        }
        public static void Subscribe(string topic, MqttQos qos, Func<string, object, bool> callback)
        {
            if (mqttClient == null)
            {
                throw new InvalidOperationException("You must call Connect() on the MqttClientManager before attempting to subscribe");
            }

            // if we don't have any for this topic yet, subscribe with the topic.
            if (subscriptions.Count(x => x.Topic == topic) == 0)
            {
                mqttClient.Subscribe(topic, qos, MessageReceiver);
            }

            // add it to the subscriptions list
            PublishSubscription pSub = new PublishSubscription(topic, callback);
            subscriptions.Add(pSub);
        }
Exemple #10
0
        static void DecodeSubAckPayload(IByteBuffer buffer, SubAckPacket packet, ref int remainingLength)
        {
            var returnCodes = new MqttQos[remainingLength];

            for (int i = 0; i < remainingLength; i++)
            {
                var returnCode = (MqttQos)buffer.ReadByte();
                if (returnCode > MqttQos.ExactlyOnce && returnCode != MqttQos.Failure)
                {
                    throw new DecoderException($"[MQTT-3.9.3-2]. Invalid return code: {returnCode}");
                }
                returnCodes[i] = returnCode;
            }
            packet.ReturnCodes = returnCodes;

            remainingLength = 0;
        }
Exemple #11
0
        public override void Decode(IByteBuffer buffer)
        {
            base.Decode(buffer);

            var returnCodes = new MqttQos[RemaingLength];

            for (int i = 0; i < RemaingLength; i++)
            {
                var returnCode = (MqttQos)buffer.ReadByte();
                if (returnCode > MqttQos.ExactlyOnce && returnCode != MqttQos.Failure)
                {
                    throw new DecoderException($"[MQTT-3.9.3-2]. Invalid return code: {returnCode}");
                }
                returnCodes[i] = returnCode;
            }
            ReturnCodes = returnCodes;
            FixedHeader.RemaingLength = 0;
        }
Exemple #12
0
        public ushort Publish(string topic, byte[] message, MqttQos qos = MqttQos.AtMostOnce, bool retained = false)
        {
            if (IsDisposed)
            {
                throw new ObjectDisposedException("MqttConnection");
            }
            else if (!IsConnected)
            {
                throw new InvalidOperationException("Not connected");
            }

            return(Publish(new PublishPacket()
            {
                Topic = topic,
                Message = message,
                QosLevel = qos,
                Retain = retained
            }));
        }
Exemple #13
0
        public void GetSubscriptionWithValidTopicReturnsSubscription()
        {
            Func <MqttMessage, bool> theCallback = null;
            var chMock = new Mock <IMqttConnectionHandler>();

            chMock.Setup((x) => x.RegisterForMessage(MqttMessageType.SubscribeAck, It.IsAny <Func <MqttMessage, bool> >()))
            .Callback((MqttMessageType msgtype, Func <MqttMessage, bool> cb) => theCallback = cb);

            string  topic = "testtopic";
            MqttQos qos   = MqttQos.AtMostOnce;

            // run and verify the mocks were called.
            Nmqtt.SubscriptionsManager subs = new Nmqtt.SubscriptionsManager(chMock.Object);
            var subid = subs.RegisterSubscription <AsciiPublishDataConverter>(topic, qos);

            // execute the callback that would normally be initiated by the connection handler when a sub ack message arrived.
            theCallback(new MqttSubscribeAckMessage().WithMessageIdentifier(subid).AddQosGrant(MqttQos.AtMostOnce));

            Assert.NotNull(subs.GetSubscription(topic));
        }
Exemple #14
0
        /// <summary>
        /// Registers a new subscription with the subscription manager.
        /// </summary>
        /// <param name="topic"></param>
        /// <param name="qos"></param>
        /// <returns>The subscription message identifier.</returns>
        internal short RegisterSubscription <TPublishDataConverter>(string topic, MqttQos qos)
            where TPublishDataConverter : IPublishDataConverter
        {
            // check we don't have a pending subscription request for the topic.
            var pendingSubs = from ps in pendingSubscriptions.Values
                              where ps.Topic.Equals(topic)
                              select ps;

            if (pendingSubs.Count <Subscription>() > 0)
            {
                throw new ArgumentException("There is already a pending subscription for this topic");
            }

            // no pending subscription, if we already have a subscription then throw it back out as well
            if (subscriptions.ContainsKey(topic))
            {
                // TODO: we might want to treat this as an ignore/silent confirm because they will be receiving messages for the topic already
                throw new ArgumentException("You are already subscribed for this topic");
            }

            // Add a pending subscription...
            Subscription sub = new Subscription()
            {
                Topic             = topic,
                Qos               = qos,
                MessageIdentifier = MessageIdentifierDispenser.GetNextMessageIdentifier("subscriptions"),
                CreatedTime       = DateTime.Now,
                DataProcessor     = Activator.CreateInstance <TPublishDataConverter>()
            };

            pendingSubscriptions.Add(sub.MessageIdentifier, sub);

            // build a subscribe message for the caller.
            MqttSubscribeMessage msg = new MqttSubscribeMessage()
                                       .WithMessageIdentifier(sub.MessageIdentifier)
                                       .ToTopic(sub.Topic)
                                       .AtQos(sub.Qos);

            connectionHandler.SendMessage(msg);
            return(msg.VariableHeader.MessageIdentifier);
        }
Exemple #15
0
        /// <summary>
        ///     Publish a message to the broker on the specified topic.
        /// </summary>
        /// <param name="topic">The topic to send the message to.</param>
        /// <param name="qualityOfService">The QOS to use when publishing the message.</param>
        /// <param name="data">The message to send.</param>
        /// <returns>The message identifier assigned to the message.</returns>
        public short Publish<T, TPayloadConverter>(string topic, MqttQos qualityOfService, T data)
            where TPayloadConverter : IPayloadConverter<T>, new() {
            var msgId = messageIdentifierDispenser.GetNextMessageIdentifier(String.Format("Topic:{0}", topic));

            Log.DebugFormat("Publishing message ID {0} on topic {1} using QOS {2}", msgId, topic, qualityOfService);

            var converter = GetPayloadConverter<TPayloadConverter>();
            var msg = new MqttPublishMessage()
                .ToTopic(topic)
                .WithMessageIdentifier(msgId)
                .WithQos(qualityOfService)
                .PublishData(converter.ConvertToBytes(data));

            // QOS level 1 or 2 messages need to be saved so we can do the ack processes
            if (qualityOfService == MqttQos.AtLeastOnce || qualityOfService == MqttQos.ExactlyOnce) {
                publishedMessages.Add(msgId, msg);
            }

            connectionHandler.SendMessage(msg);
            return msgId;
        }
Exemple #16
0
        void IMqttSession.Publish(string messageId, MqttQos qos)
        {
            var publish = new PendingPublishMessage(1, messageId, qos);

            //WARNING: Something you may not expect
            //SetResult will transfer control to a waiter if there is one. We need to get our queue straight before that happens
            //Or else whack shit goes wrong. So don't go thinking "it's prettier to see if the queue is empty before queueing".
            //Not that this was ever coded that way or anything...
            pendingMessages.Enqueue(publish);
            //If this is the first message, signal.
            if (pendingMessages.Count == 1 && pendingMessageCompletionSource != null)
            {
                TaskCompletionSource <PendingMessage> source = pendingMessageCompletionSource;
                pendingMessageCompletionSource = null;
                source.SetResult(publish);
            }
            if (qos == MqttQos.BestEffort)
            {
                pendingMessages.Enqueue(new PendingPubRelMessage(1));
            }
        }
Exemple #17
0
        /// <summary>
        /// Publish a message to the broker on the specified topic.
        /// </summary>
        /// <param name="topic">The topic to send the message to.</param>
        /// <param name="payload">The message to send.</param>
        /// <returns>The message identifier assigned to the message.</returns>
        public short Publish <TDataConverter>(string topic, MqttQos qualityOfService, object data)
            where TDataConverter : IPublishDataConverter
        {
            short msgID = MessageIdentifierDispenser.GetNextMessageIdentifier(String.Format("Topic:{0}", topic));

            IPublishDataConverter converter = GetPublishDataConverter <TDataConverter>();

            MqttPublishMessage msg = new MqttPublishMessage()
                                     .ToTopic(topic)
                                     .WithMessageIdentifier(msgID)
                                     .WithQos(qualityOfService)
                                     .PublishData(converter.ConvertToBytes(data));

            // QOS level 1 or 2 messages need to be saved so we can do the ack processes
            if (qualityOfService == MqttQos.AtLeastOnce || qualityOfService == MqttQos.ExactlyOnce)
            {
                publishedMessages.Add(msgID, msg);
            }

            connectionHandler.SendMessage(msg);

            return(msgID);
        }
Exemple #18
0
        public void SubscriptionRequestInvokesSend()
        {
            MqttSubscribeMessage subMsg = null;

            var chMock = new Mock <IMqttConnectionHandler>();

            // mock the call to register and save the callback for later.
            chMock.Setup((x) => x.RegisterForMessage(MqttMessageType.SubscribeAck, It.IsAny <Func <MqttMessage, bool> >()));
            // mock the call to Send(), which should occur when the subscription manager tries to subscribe
            chMock.Setup(x => x.SendMessage(It.IsAny <MqttSubscribeMessage>()))
            .Callback((MqttMessage msg) => subMsg = (MqttSubscribeMessage)msg);

            string  topic = "testtopic";
            MqttQos qos   = MqttQos.AtMostOnce;

            // run and verify the mocks were called.
            Nmqtt.SubscriptionsManager subs = new Nmqtt.SubscriptionsManager(chMock.Object);
            subs.RegisterSubscription <AsciiPublishDataConverter>(topic, qos);
            chMock.VerifyAll();

            // now check the message generated by the subscription manager was good - ie contain the topic at the specified qos
            Assert.Contains(topic, subMsg.Payload.Subscriptions.Keys);
            Assert.Equal <MqttQos>(MqttQos.AtMostOnce, subMsg.Payload.Subscriptions[topic]);
        }
Exemple #19
0
 /// <summary>
 /// Sets the Qos of the message header.
 /// </summary>
 /// <param name="qos">The Qos to ser</param>
 /// <returns>An instance of the header.</returns>
 public MqttHeader WithQos(MqttQos qos)
 {
     this.Qos = qos;
     return(this);
 }
Exemple #20
0
 /// <summary>
 ///     Publishes a message to the message broker.
 /// </summary>
 /// <param name="topic">The topic to publish the message to.</param>
 /// <param name="qos">The QOS level to publish the message at.</param>
 /// <param name="data">The message to publish.</param>
 /// <returns>The message identiier assigned to the message.</returns>
 public short PublishMessage(string topic, MqttQos qos, byte[] data)
 {
     return(PublishMessage <byte[], PassThroughPayloadConverter>(topic, qos, data));
 }
Exemple #21
0
        public IObservable <MqttReceivedMessage <T> > ListenTo <T, TPayloadConverter>(string topic, MqttQos qosLevel)
            where TPayloadConverter : IPayloadConverter <T>, new()
        {
            if (connectionHandler.State != ConnectionState.Connected)
            {
                throw new ConnectionException(connectionHandler.State);
            }

            return(subscriptionsManager.RegisterSubscription <T, TPayloadConverter>(topic, qosLevel));
        }
Exemple #22
0
 /// <summary>
 ///     Subscribles the specified topic with a callback function that accepts the raw message data.
 /// </summary>
 /// <param name="topic">The topic.</param>
 /// <param name="qosLevel">The qos level.</param>
 /// <returns></returns>
 /// <exception cref="InvalidTopicException">If a topic that does not meet the MQTT topic spec rules is provided.</exception>
 public IObservable <MqttReceivedMessage <byte[]> > ListenTo(string topic, MqttQos qosLevel)
 {
     return(ListenTo <byte[], PassThroughPayloadConverter>(topic, qosLevel));
 }
 /// <summary>
 ///     Sets the WillQos of the connect flag.
 /// </summary>
 /// <param name="qos">The qos.</param>
 /// <returns></returns>
 public MqttConnectMessage WithWillQos(MqttQos qos) {
     this.VariableHeader.ConnectFlags.WillQos = qos;
     return this;
 }
 /// <summary>
 /// Adds a subscription grant to the message.
 /// </summary>
 /// <param name="qosGranted">The granted Qos to add.</param>
 /// <returns>The updated instance of the message.</returns>
 public MqttSubscribeAckMessage AddQosGrant(MqttQos qosGranted)
 {
     this.Payload.AddGrant(qosGranted);
     return this;
 }
 /// <summary>
 ///     Sets the Qos of the published message.
 /// </summary>
 /// <param name="qos">The qos to set.</param>
 /// <returns>The updated instance of the message.</returns>
 public MqttPublishMessage WithQos(MqttQos qos) {
     this.Header.WithQos(qos);
     return this;
 }
Exemple #26
0
 public void Subscribe(string topic, MqttQos qosLevel)
 {
     Subscribe(new string[] { topic }, new MqttQos[] { qosLevel });
 }
 /// <summary>
 ///     Adds a new subscription to the collection of subscriptions.
 /// </summary>
 /// <param name="grantedQos">The granted qos.</param>
 public void AddGrant(MqttQos grantedQos) {
     qosGrants.Add(grantedQos);
 }
Exemple #28
0
 public MqttSubscriberConstrains(string subsciberId, MqttQos qos)
 {
     this.SubsciberId = subsciberId;
     this.Qos         = qos;
 }
 /// <summary>
 ///     Adds a subscription grant to the message.
 /// </summary>
 /// <param name="qosGranted">The granted Qos to add.</param>
 /// <returns>The updated instance of the message.</returns>
 public MqttSubscribeAckMessage AddQosGrant(MqttQos qosGranted)
 {
     this.Payload.AddGrant(qosGranted);
     return(this);
 }
Exemple #30
0
        public MqttClient(NumbersPersistence numbersPersistence, IMqttPersistence clientPersistence, string topicRoot, string clientId, MqttQos qos, int maxNumber)
        {
            this.clientPersistence  = clientPersistence;
            this.numbersPersistence = numbersPersistence;

            ClientId         = clientId;
            TopicToPublish   = topicRoot + "/" + clientId;
            TopicToSubscribe = topicRoot + "/#";
            Qos = qos;

            this.maxNumber = maxNumber;
            this.previousPublishedNumber = numbersPersistence.GetLastNumberSent();
        }
Exemple #31
0
 /// <summary>
 ///     Sets the Qos of the message header.
 /// </summary>
 /// <param name="qos">The Qos to ser</param>
 /// <returns>An instance of the header.</returns>
 public MqttHeader WithQos(MqttQos qos) {
     this.Qos = qos;
     return this;
 }
 /// <summary>
 ///     Adds a new subscription to the collection of subscriptions.
 /// </summary>
 /// <param name="grantedQos">The granted qos.</param>
 public void AddGrant(MqttQos grantedQos)
 {
     qosGrants.Add(grantedQos);
 }
Exemple #33
0
        /// <summary>
        ///     Creates a new subscription for the specified topic.
        /// </summary>
        /// <typeparam name="T">The type of data the subscription is expected to return.</typeparam>
        /// <typeparam name="TPayloadConverter">The type of the converter that can convert from bytes to the type T.</typeparam>
        /// <param name="topic">The topic to subscribe to.</param>
        /// <param name="qos">The QOS level to subscribe at.</param>
        /// <returns>An observable that yields messages when they arrive.</returns>
        /// <exception cref="InvalidTopicException">If a topic that does not meet the MQTT topic spec rules is provided.</exception>
        private IObservable <MqttReceivedMessage <T> > CreateNewSubscription <T, TPayloadConverter>(string topic, MqttQos qos)
            where TPayloadConverter : IPayloadConverter <T>, new()
        {
            Log.Info(m => m("Creating subscription for topoc {0} @ QOS {1}.", topic, qos));

            try {
                var subscriptionTopic = new SubscriptionTopic(topic);

                // Get an ID that represents the subscription. We will use this same ID for unsubscribe as well.
                var msgId = messageIdentifierDispenser.GetNextMessageIdentifier("subscriptions");

                // create a new observable that is used to yield messages
                // that arrive for the topoc.
                var observable = CreateObservableForSubscription(subscriptionTopic, msgId);

                var sub = new Subscription {
                    Topic             = subscriptionTopic,
                    Qos               = qos,
                    MessageIdentifier = msgId,
                    CreatedTime       = DateTime.Now,
                    Observable        = observable,
                };

                pendingSubscriptions.Add(sub.MessageIdentifier, sub);

                // build a subscribe message for the caller and send it off to the broker.
                var msg = new MqttSubscribeMessage().WithMessageIdentifier(sub.MessageIdentifier)
                          .ToTopic(sub.Topic.ToString())
                          .AtQos(sub.Qos);
                connectionHandler.SendMessage(msg);

                return(WrapSubscriptionObservable <T, TPayloadConverter>(sub.Observable));
            } catch (ArgumentException ex) {
                Log.Warn(m => m("Error while processing topoc {0}. topoc structure not valid.", topic), ex);
                throw new InvalidTopicException(ex.Message, topic, ex);
            }
        }
Exemple #34
0
 /// <summary>
 /// 订阅主题
 /// </summary>
 /// <param name="topic">主题</param>
 /// <param name="qos">服务质量等级</param>
 public void Add(string topic, MqttQos qos)
 {
     _subscribeTopics.Add(new SubscriptionRequest(topic, qos));
 }
Exemple #35
0
 /// <summary>
 ///     Registers a new subscription with the subscription manager.
 /// </summary>
 /// <param name="topic"></param>
 /// <param name="qos"></param>
 /// <returns>An IObservable that yields any messages received once subscribed.</returns>
 /// <exception cref="InvalidTopicException">If a topic that does not meet the MQTT topic spec rules is provided.</exception>
 public IObservable <MqttReceivedMessage <T> > RegisterSubscription <T, TPayloadConverter>(string topic, MqttQos qos)
     where TPayloadConverter : IPayloadConverter <T>, new()
 {
     // if we have a pending subscription or established subscription just return the existing observable.
     lock (subscriptionPadlock) {
         IObservable <MqttReceivedMessage <T> > existingObservable;
         if (TryGetExistingSubscription <T, TPayloadConverter>(topic, out existingObservable))
         {
             return(existingObservable);
         }
         return(CreateNewSubscription <T, TPayloadConverter>(topic, qos));
     }
 }
Exemple #36
0
 public SubscriptionRequest(string topic, MqttQos qos)
 {
     Topic = topic;
     Qos   = qos;
 }
Exemple #37
0
 /// <summary>
 ///     Adds a new subscription to the collection of subscriptions.
 /// </summary>
 /// <param name="topic">The topic to subscribe to.</param>
 /// <param name="qos">The qos level to subscribe at.</param>
 public void AddSubscription(string topic, MqttQos qos) {
     if (Subscriptions.ContainsKey(topic)) {
         Subscriptions[topic] = qos;
     } else {
         Subscriptions.Add(topic, qos);
     }
 }
Exemple #38
0
 /// <summary>
 ///     Sets the WillQos of the connect flag.
 /// </summary>
 /// <param name="qos">The qos.</param>
 /// <returns></returns>
 public MqttConnectMessage WithWillQos(MqttQos qos)
 {
     this.VariableHeader.ConnectFlags.WillQos = qos;
     return(this);
 }
 /// <summary>
 /// Writes the fixed header with the specified qos level and flags zeroed.
 /// </summary>
 /// <param name="packetType">Packet type.</param>
 /// <param name="qosLevel">Qos level.</param>
 internal void SetFixedHeader(byte packetType, MqttQos qosLevel)
 {
     fixedHeader  = (byte)(packetType << Packet.PacketTypeOffset);
     fixedHeader |= (byte)((byte)qosLevel << Packet.QosLevelOffset);
 }