@@ -2,7 +2,9 @@ use std::collections::{HashMap, VecDeque};
22use std:: time:: { Duration , Instant } ;
33
44use crate :: mqtt_serde:: control_packet:: MqttPacket ;
5- use crate :: mqtt_serde:: mqttv3:: { connectv3, disconnectv3, pingreqv3, pubrelv3, unsubscribev3} ;
5+ use crate :: mqtt_serde:: mqttv3:: {
6+ connectv3, disconnectv3, pingreqv3, pubrelv3, subscribev3, unsubscribev3,
7+ } ;
68use crate :: mqtt_serde:: mqttv5:: {
79 authv5, common:: properties:: Property , connectv5, disconnectv5, pingreqv5, pubackv5:: MqttPubAck ,
810 pubcompv5:: MqttPubComp , publishv5:: MqttPublish , pubrecv5:: MqttPubRec , pubrelv5:: MqttPubRel ,
@@ -19,6 +21,13 @@ use super::commands::{PublishCommand, SubscribeCommand, UnsubscribeCommand};
1921use super :: error:: MqttClientError ;
2022use super :: opts:: MqttClientOptions ;
2123
24+ /// Alias for `MqttPublish` (v5) to provide a single, unified type for received messages.
25+ ///
26+ /// The engine normalizes all incoming PUBLISH packets (whether MQTT v3.1.1 or v5.0) into this structure.
27+ /// This simplifies downstream consumption by providing a consistent API regardless of the protocol version used.
28+ /// For MQTT v3.1.1 messages, the v5-specific fields (Properties) will be empty.
29+ pub type MqttMessage = MqttPublish ;
30+
2231/// Events emitted by the MqttEngine to be handled by the application (I/O layer)
2332#[ derive( Debug ) ]
2433pub enum MqttEvent {
@@ -27,7 +36,7 @@ pub enum MqttEvent {
2736 Published ( PublishResult ) ,
2837 Subscribed ( SubscribeResult ) ,
2938 Unsubscribed ( UnsubscribeResult ) ,
30- MessageReceived ( MqttPublish ) ,
39+ MessageReceived ( MqttMessage ) ,
3140 PingResponse ( PingResult ) ,
3241 Error ( MqttClientError ) ,
3342 /// Signal that a reconnection is needed (e.g. after keep-alive timeout)
@@ -74,7 +83,7 @@ pub enum MqttEvent {
7483pub struct MqttEngine {
7584 options : MqttClientOptions ,
7685 session : Option < ClientSession > ,
77- priority_queue : PriorityQueue < u8 , PublishCommand > ,
86+ priority_queue : PriorityQueue < u8 , MqttPacket > ,
7887 is_connected : bool ,
7988 last_packet_sent : Instant ,
8089 last_packet_received : Instant ,
@@ -88,7 +97,6 @@ pub struct MqttEngine {
8897 pending_unsubscribes : HashMap < u16 , Vec < String > > ,
8998 pending_publishes : HashMap < u16 , Instant > ,
9099
91- mqtt_version : u8 ,
92100 events : Vec < MqttEvent > ,
93101
94102 // Reconnection state
@@ -132,7 +140,6 @@ impl MqttEngine {
132140 pending_subscribes : HashMap :: new ( ) ,
133141 pending_unsubscribes : HashMap :: new ( ) ,
134142 pending_publishes : HashMap :: new ( ) ,
135- mqtt_version,
136143 events : Vec :: new ( ) ,
137144 reconnect_attempts : 0 ,
138145 next_reconnect_at : None ,
@@ -250,7 +257,7 @@ impl MqttEngine {
250257 }
251258
252259 pub fn mqtt_version ( & self ) -> u8 {
253- self . mqtt_version
260+ self . options . mqtt_version
254261 }
255262
256263 /// Process time-dependent logic (keep-alive, timeouts, retransmissions).
@@ -306,7 +313,7 @@ impl MqttEngine {
306313
307314 // MQTT v5.0: Client MUST NOT retransmit PUBLISH packets
308315 // Only MQTT v3.1.1 allows client-side retransmission with DUP=1
309- if self . mqtt_version == 5 {
316+ if self . options . mqtt_version == 5 {
310317 return events;
311318 }
312319
@@ -367,7 +374,7 @@ impl MqttEngine {
367374
368375 // 4. Retransmission timeouts (QoS 1/2 messages)
369376 // Only for MQTT v3.1.1, as v5.0 forbids client-side retransmission
370- if self . mqtt_version != 5 {
377+ if self . options . mqtt_version != 5 {
371378 for & sent_at in self . pending_publishes . values ( ) {
372379 let resend_at = sent_at + self . retransmission_timeout ;
373380 if next. is_none ( ) || resend_at < next. unwrap ( ) {
@@ -406,7 +413,7 @@ impl MqttEngine {
406413 self . session = Some ( ClientSession :: new ( ) ) ;
407414 }
408415
409- let packet = if self . mqtt_version == 5 {
416+ let packet = if self . options . mqtt_version == 5 {
410417 let connect = connectv5:: MqttConnect :: new (
411418 self . options . client_id . clone ( ) ,
412419 self . options . username . clone ( ) ,
@@ -453,7 +460,13 @@ impl MqttEngine {
453460 self . pending_publishes . insert ( pid, Instant :: now ( ) ) ;
454461 }
455462
456- self . priority_queue . enqueue ( command. priority , command) ;
463+ let packet = if self . options . mqtt_version == 5 {
464+ MqttPacket :: Publish5 ( command. to_mqtt_publish ( ) )
465+ } else {
466+ MqttPacket :: Publish3 ( command. to_mqttv3_publish ( ) )
467+ } ;
468+
469+ self . priority_queue . enqueue ( command. priority , packet) ;
457470 self . process_queue ( ) ;
458471 Ok ( pid)
459472 }
@@ -478,11 +491,23 @@ impl MqttEngine {
478491 . collect ( ) ;
479492 self . pending_subscribes . insert ( pid, topics) ;
480493
481- let packet = MqttPacket :: Subscribe5 ( subscribev5:: MqttSubscribe :: new (
482- pid,
483- command. subscriptions ,
484- command. properties ,
485- ) ) ;
494+ let packet = if self . options . mqtt_version == 5 {
495+ MqttPacket :: Subscribe5 ( subscribev5:: MqttSubscribe :: new (
496+ pid,
497+ command. subscriptions ,
498+ command. properties ,
499+ ) )
500+ } else {
501+ let v3_subs = command
502+ . subscriptions
503+ . into_iter ( )
504+ . map ( |s| subscribev3:: SubscriptionTopic {
505+ topic_filter : s. topic_filter ,
506+ qos : s. qos ,
507+ } )
508+ . collect ( ) ;
509+ MqttPacket :: Subscribe3 ( subscribev3:: MqttSubscribe :: new ( pid, v3_subs) )
510+ } ;
486511
487512 self . enqueue_packet ( packet) ?;
488513 Ok ( pid)
@@ -500,7 +525,7 @@ impl MqttEngine {
500525 self . pending_unsubscribes
501526 . insert ( pid, command. topics . clone ( ) ) ;
502527
503- let packet = if self . mqtt_version == 5 {
528+ let packet = if self . options . mqtt_version == 5 {
504529 MqttPacket :: Unsubscribe5 ( unsubscribev5:: MqttUnsubscribe :: new (
505530 pid,
506531 command. topics . clone ( ) ,
@@ -520,7 +545,7 @@ impl MqttEngine {
520545 return ;
521546 }
522547
523- let packet = if self . mqtt_version == 5 {
548+ let packet = if self . options . mqtt_version == 5 {
524549 MqttPacket :: Disconnect5 ( disconnectv5:: MqttDisconnect :: new ( 0 , Vec :: new ( ) ) )
525550 } else {
526551 MqttPacket :: Disconnect3 ( disconnectv3:: MqttDisconnect :: new ( ) )
@@ -531,7 +556,7 @@ impl MqttEngine {
531556 }
532557
533558 pub fn auth ( & mut self , reason_code : u8 , properties : Vec < Property > ) {
534- if self . mqtt_version == 5 {
559+ if self . options . mqtt_version == 5 {
535560 let auth = authv5:: MqttAuth :: new ( reason_code, properties) ;
536561 let _ = self . enqueue_packet ( MqttPacket :: Auth ( auth) ) ;
537562 }
@@ -715,7 +740,7 @@ impl MqttEngine {
715740 }
716741
717742 pub fn send_ping ( & mut self ) {
718- let packet = if self . mqtt_version == 5 {
743+ let packet = if self . options . mqtt_version == 5 {
719744 MqttPacket :: PingReq5 ( pingreqv5:: MqttPingReq :: new ( ) )
720745 } else {
721746 MqttPacket :: PingReq3 ( pingreqv3:: MqttPingReq :: new ( ) )
@@ -744,33 +769,7 @@ impl MqttEngine {
744769 }
745770
746771 while self . outgoing_buffer . len ( ) < self . options . max_outgoing_packet_count {
747- if let Some ( ( _priority, mut command) ) = self . priority_queue . dequeue ( ) {
748- let _pid = if command. qos > 0 {
749- if let Some ( pid) = command. packet_id {
750- Some ( pid)
751- } else {
752- match self . next_packet_id ( ) {
753- Ok ( id) => {
754- self . pending_publishes . insert ( id, Instant :: now ( ) ) ;
755- command. packet_id = Some ( id) ;
756- Some ( id)
757- }
758- Err ( e) => {
759- self . events . push ( MqttEvent :: Error ( e) ) ;
760- continue ;
761- }
762- }
763- }
764- } else {
765- None
766- } ;
767-
768- let packet = if self . mqtt_version == 5 {
769- MqttPacket :: Publish5 ( command. to_mqtt_publish ( ) )
770- } else {
771- MqttPacket :: Publish3 ( command. to_mqttv3_publish ( ) )
772- } ;
773-
772+ if let Some ( ( _priority, packet) ) = self . priority_queue . dequeue ( ) {
774773 if let Err ( e) = self . enqueue_packet ( packet) {
775774 self . events . push ( MqttEvent :: Error ( e) ) ;
776775 }
0 commit comments