public void AddInflightMessage(MqttMsgBase packet) { MqttMsgContext context = new MqttMsgContext(); Del d = delegate() { return(packet.QosLevel == (byte)0x01 ? MqttMsgState.QueuedQos1 : MqttMsgState.QueuedQos2); }; MqttMsgState state = packet.QosLevel == (byte)0x00 ? MqttMsgState.QueuedQos0 : d(); context.State = state; context.Message = packet; session.InflightMessages.Add(packet.MessageId, context); }
public void ChangeMsgState(ushort messageId, MqttMsgState state) { session.InflightMessages[messageId].State = state; }
private static void EnqueueInflight(MqttClientConnection clientConnection, 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)) { // 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 clientConnection 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(msg.MessageId, MqttMsgFlow.ToAcknowledge); MqttMsgContext msgCtx = (MqttMsgContext)clientConnection.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 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; } // [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 MqttMsgContext msgContext = new MqttMsgContext() { Message = msg, State = state, Flow = flow, Attempt = 0 }; // enqueue message and unlock send thread clientConnection.EnqueueInflight(msgContext); // PUBLISH message if (msg.Type == MqttMsgBase.MQTT_MSG_PUBLISH_TYPE) { // to publish and QoS level 1 or 2 if ((msgContext.Flow == MqttMsgFlow.ToPublish) && ((msg.QosLevel == MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE) || (msg.QosLevel == MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE))) { if (clientConnection.Session != null) { clientConnection.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 (clientConnection.Session != null) { clientConnection.Session.InflightMessages.TryAdd(msgContext.Key, msgContext); } } } } }