コード例 #1
0
ファイル: MqttClient.cs プロジェクト: XSockets/MQTT
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="messageId">Message Id</param>
 /// <param name="flow">Message flow inside inflight queue</param>
 internal MqttMsgContextFinder(ushort messageId, MqttMsgFlow flow)
 {
     this.MessageId = messageId;
     this.Flow = flow;
 }
コード例 #2
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="messageId">Message Id</param>
 /// <param name="flow">Message flow inside inflight queue</param>
 internal MqttMsgContextFinder(ushort messageId, MqttMsgFlow flow)
 {
     MessageId = messageId;
     Flow      = flow;
 }
コード例 #3
0
ファイル: MqttClient.cs プロジェクト: jimy811111/Unity3d_MQTT
        /// <summary>
        /// Enqueue a message into the inflight queue
        /// </summary>
        /// <param name="msg">Message to enqueue</param>
        /// <param name="flow">Message flow (publish, acknowledge)</param>
        private void EnqueueInflight(MqttMsgBase msg, MqttMsgFlow flow)
        {
            // enqueue is needed (or not)
            bool enqueue = true;

            // if it is a PUBLISH message with QoS Level 2
            if ((msg.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE) &&
                (msg.QosLevel == MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE))
            {
                lock (this.inflightQueue)
                {
                    // if it is a PUBLISH message already received (it is in the inflight queue), the publisher
                    // re-sent it because it didn't received the PUBREC. In this case, we have to re-send PUBREC

                    // NOTE : I need to find on message id and flow because the broker could be publish/received
                    //        to/from client and message id could be the same (one tracked by broker and the other by client)
                    MqttMsgContextFinder msgCtxFinder = new MqttMsgContextFinder(((MqttMsgPublish)msg).MessageId, MqttMsgFlow.ToAcknowledge);
                    MqttMsgContext msgCtx = (MqttMsgContext)this.inflightQueue.Get(msgCtxFinder.Find);

                    // the PUBLISH message is alredy in the inflight queue, we don't need to re-enqueue but we need
                    // to change state to re-send PUBREC
                    if (msgCtx != null)
                    {
                        msgCtx.State = MqttMsgState.QueuedQos2;
                        msgCtx.Flow = MqttMsgFlow.ToAcknowledge;
                        enqueue = false;
                    }
                }
            }

            if (enqueue)
            {
                // set a default state
                MqttMsgState state = MqttMsgState.QueuedQos0;

                // based on QoS level, the messages flow between broker and client changes
                switch (msg.QosLevel)
                {
                    // QoS Level 0
                    case MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE:

                        state = MqttMsgState.QueuedQos0;
                        break;

                    // QoS Level 1
                    case MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE:

                        state = MqttMsgState.QueuedQos1;
                        break;

                    // QoS Level 2
                    case MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE:

                        state = MqttMsgState.QueuedQos2;
                        break;
                }

                // queue message context
                MqttMsgContext msgContext = new MqttMsgContext()
                {
                    Message = msg,
                    State = state,
                    Flow = flow,
                    Attempt = 0
                };

                lock (this.inflightQueue)
                {
                    // enqueue message and unlock send thread
                    this.inflightQueue.Enqueue(msgContext);
                }
            }

            this.inflightWaitHandle.Set();
        }
コード例 #4
0
        private void EnqueueInflight(MqttConnection connection, MqttMsgBase msg, MqttMsgFlow flow)
        {
            // enqueue is needed (or not)
            var enqueue = true;

            // if it is a PUBLISH message with QoS Level 2
            if (msg.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE && msg.QosLevel == MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE)
            {
                // if it is a PUBLISH message already received (it is in the inflight queue), the publisher
                // re-sent it because it didn't received the PUBREC. In connection case, we have to re-send PUBREC

                // NOTE : I need to find on message id and flow because the broker could be publish/received
                // to/from client and message id could be the same (one tracked by broker and the other by client)
                var msgCtxFinder = new MqttMsgContextFinder(msg.MessageId, MqttMsgFlow.ToAcknowledge);
                var msgCtx       = (MqttMsgContext)connection.InflightQueue.FirstOrDefault(msgCtxFinder.Find);

                // the PUBLISH message is alredy in the inflight queue, we don't need to re-enqueue but we need
                // to change state to re-send PUBREC
                if (msgCtx != null)
                {
                    msgCtx.State = MqttMsgState.QueuedQos2;
                    msgCtx.Flow  = MqttMsgFlow.ToAcknowledge;
                    enqueue      = false;
                }
            }

            if (enqueue)
            {
                // set a default state
                var state = MqttMsgState.QueuedQos0;

                // based on QoS level, the messages flow between broker and client changes
                switch (msg.QosLevel)
                {
                // QoS Level 0
                case MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE:
                    state = MqttMsgState.QueuedQos0;
                    break;

                // QoS Level 1
                case MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE:
                    state = MqttMsgState.QueuedQos1;
                    break;

                // QoS Level 2
                case MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE:
                    state = MqttMsgState.QueuedQos2;
                    break;
                }

                // [v3.1.1] SUBSCRIBE and UNSUBSCRIBE aren't "officially" QOS = 1
                // so QueuedQos1 state isn't valid for them
                if (msg.Type == MqttMsgBase.MQTT_MSG_SUBSCRIBE_TYPE)
                {
                    state = MqttMsgState.SendSubscribe;
                }
                else if (msg.Type == MqttMsgBase.MQTT_MSG_UNSUBSCRIBE_TYPE)
                {
                    state = MqttMsgState.SendUnsubscribe;
                }

                // queue message context
                var msgContext = new MqttMsgContext()
                {
                    Message = msg,
                    State   = state,
                    Flow    = flow,
                    Attempt = 0
                };

                // enqueue message and unlock send thread
                connection.EnqueueInflight(msgContext);

                // PUBLISH message
                if (msg.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE)
                {
                    if (msgContext.Flow == MqttMsgFlow.ToPublish &&
                        (msg.QosLevel == MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE ||
                         msg.QosLevel == MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE))
                    {
                        if (connection.Session != null)
                        {
                            connection.Session.InflightMessages.TryAdd(msgContext.Key, msgContext);
                        }
                    }

                    // to acknowledge and QoS level 2
                    else if (msgContext.Flow == MqttMsgFlow.ToAcknowledge &&
                             msg.QosLevel == MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE)
                    {
                        if (connection.Session != null)
                        {
                            connection.Session.InflightMessages.TryAdd(msgContext.Key, msgContext);
                        }
                    }
                }
            }
        }