Example #1
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>
        private IObservable <MqttReceivedMessage <T> > CreateNewSubscription <T, TPayloadConverter>(string topic, MqttQos qos)
            where TPayloadConverter : IPayloadConverter <T>, new()
        {
            Log.Info(m => m("Creating subscription for topic {0} @ QOS {1}.", topic, qos));

            // 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 topic.
            var observable = CreateObservableForSubscription(topic, msgId);

            var sub = new Subscription {
                Topic             = topic,
                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)
                      .AtQos(sub.Qos);

            connectionHandler.SendMessage(msg);

            return(WrapSubscriptionObservable <T, TPayloadConverter>(topic, sub.Observable));
        }
Example #2
0
 /// <summary>
 ///     Pings the message broker if there has been no activity for the specified amount of idle time.
 /// </summary>
 /// <param name="state"></param>
 private void PingRequired(object state)
 {
     // if we can't get the montor then the connection has been / is currently being disposed, so
     // we don't want to do a ping (the connection handler might no longer be valid)
     if (Monitor.TryEnter(shutdownPadlock))
     {
         try {
             var pingMsg = new MqttPingRequestMessage();
             connectionHandler.SendMessage(pingMsg);
         } finally {
             Monitor.Exit(shutdownPadlock);
         }
     }
 }
Example #3
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;
        }
Example #4
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);
        }
Example #5
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);
        }