mqute_codec/protocol/v5/
packet.rs

1//! # MQTT v5 Packet Enumeration
2//!
3//! This module provides a unified `Packet` enum that represents all possible MQTT v5 packet types.
4//! It serves as the primary interface for decoding and encoding MQTT packets, handling the complete
5//! protocol specification including all control packet types.
6
7use crate::Error;
8use crate::codec::{Decode, Encode, RawPacket};
9use crate::protocol::PacketType;
10use crate::protocol::v5::{
11    Auth, ConnAck, Connect, Disconnect, PingReq, PingResp, PubAck, PubComp, PubRec, PubRel,
12    Publish, SubAck, Subscribe, UnsubAck, Unsubscribe,
13};
14
15/// Represents all possible MQTT v5 packet types
16///
17/// This enum serves as the main abstraction for working with MQTT packets,
18/// providing a unified interface for packet handling while maintaining
19/// type safety for each specific packet type.
20///
21/// # Example
22///
23/// ```rust
24/// use mqute_codec::protocol::v5::Packet;
25/// use mqute_codec::protocol::v5::{Connect, ConnectProperties};
26/// use bytes::{Bytes, BytesMut};
27///
28/// let properties = ConnectProperties {
29///     session_expiry_interval: Some(3600),
30///     ..Default::default()
31/// };
32///
33/// let connect = Connect::with_properties(
34///     "client",
35///     None,
36///     None,
37///     properties.clone(),
38///     30,
39///     true);
40///
41/// let mut buf = BytesMut::new();
42///
43/// let packet = Packet::Connect(connect);
44///
45/// packet.encode(&mut buf).unwrap()
46/// ```
47#[derive(Debug, Clone, PartialEq, Eq)]
48pub enum Packet {
49    /// Client-initiated connection request. First packet in connection establishment flow
50    Connect(Connect),
51
52    /// Server connection acknowledgment. Sent in response to CONNECT packet
53    ConnAck(ConnAck),
54
55    /// Message publication. Primary message delivery mechanism.
56    Publish(Publish),
57
58    /// QoS 1 publication acknowledgment. Acknowledges receipt of QoS 1 messages
59    PubAck(PubAck),
60
61    /// QoS 2 publication received (part 1). First packet in QoS 2 protocol flow
62    PubRec(PubRec),
63
64    /// QoS 2 publication release (part 2). Second packet in QoS 2 protocol flow
65    PubRel(PubRel),
66
67    /// QoS 2 publication complete (part 3). Final packet in QoS 2 protocol flow
68    PubComp(PubComp),
69
70    /// Subscription request. Begins subscription creation/modification
71    Subscribe(Subscribe),
72
73    /// Subscription acknowledgment. Confirms subscription processing results
74    SubAck(SubAck),
75
76    /// Unsubscription request. Begins subscription termination
77    Unsubscribe(Unsubscribe),
78
79    /// Unsubscription acknowledgment. Confirms unsubscription processing
80    UnsubAck(UnsubAck),
81
82    /// Keep-alive ping request. Must be responded to with PINGRESP
83    PingReq(PingReq),
84
85    /// Keep-alive ping response. Sent in response to PINGREQ to confirm connection is active
86    PingResp(PingResp),
87
88    /// Graceful connection termination. Properly closes the MQTT connection
89    Disconnect(Disconnect),
90
91    /// Authentication exchange. Used for extended authentication flows
92    Auth(Auth),
93}
94
95impl Packet {
96    /// Decodes a raw MQTT packet into the appropriate Packet variant
97    ///
98    /// This is the primary entry point for packet processing, handling:
99    /// - Packet type identification
100    /// - Payload validation
101    /// - Special cases for empty payload packets
102    /// - Delegation to specific packet decoders
103    pub fn decode(raw_packet: RawPacket) -> Result<Self, Error> {
104        let packet_type = raw_packet.header.packet_type();
105
106        // Handle packets that may have empty payloads
107        if raw_packet.header.remaining_len() == 0 {
108            return match packet_type {
109                PacketType::PingReq => Ok(Self::PingReq(PingReq::decode(raw_packet)?)),
110                PacketType::PingResp => Ok(Self::PingResp(PingResp::decode(raw_packet)?)),
111                PacketType::Disconnect => Ok(Self::Disconnect(Disconnect::decode(raw_packet)?)),
112                PacketType::Auth => Ok(Self::Auth(Auth::decode(raw_packet)?)),
113                _ => Err(Error::PayloadRequired),
114            };
115        }
116
117        // Dispatch to appropriate packet decoder
118        let decoded = match packet_type {
119            PacketType::Connect => Self::Connect(Connect::decode(raw_packet)?),
120            PacketType::ConnAck => Self::ConnAck(ConnAck::decode(raw_packet)?),
121            PacketType::Publish => Self::Publish(Publish::decode(raw_packet)?),
122            PacketType::PubAck => Self::PubAck(PubAck::decode(raw_packet)?),
123            PacketType::PubRec => Self::PubRec(PubRec::decode(raw_packet)?),
124            PacketType::PubRel => Self::PubRel(PubRel::decode(raw_packet)?),
125            PacketType::PubComp => Self::PubComp(PubComp::decode(raw_packet)?),
126            PacketType::Subscribe => Self::Subscribe(Subscribe::decode(raw_packet)?),
127            PacketType::SubAck => Self::SubAck(SubAck::decode(raw_packet)?),
128            PacketType::Unsubscribe => Self::Unsubscribe(Unsubscribe::decode(raw_packet)?),
129            PacketType::UnsubAck => Self::UnsubAck(UnsubAck::decode(raw_packet)?),
130            PacketType::Disconnect => Self::Disconnect(Disconnect::decode(raw_packet)?),
131            PacketType::Auth => Self::Auth(Auth::decode(raw_packet)?),
132            // Ping packets should have been handled above
133            _ => return Err(Error::MalformedPacket),
134        };
135
136        Ok(decoded)
137    }
138
139    /// Encodes the packet into its wire format
140    ///
141    /// Delegates to the specific packet implementation's encoder while
142    /// providing a unified interface for all packet types.
143    pub fn encode(&self, buf: &mut bytes::BytesMut) -> Result<(), Error> {
144        match self {
145            Self::Connect(packet) => packet.encode(buf),
146            Self::ConnAck(packet) => packet.encode(buf),
147            Self::Publish(packet) => packet.encode(buf),
148            Self::PubAck(packet) => packet.encode(buf),
149            Self::PubRec(packet) => packet.encode(buf),
150            Self::PubRel(packet) => packet.encode(buf),
151            Self::PubComp(packet) => packet.encode(buf),
152            Self::Subscribe(packet) => packet.encode(buf),
153            Self::SubAck(packet) => packet.encode(buf),
154            Self::Unsubscribe(packet) => packet.encode(buf),
155            Self::UnsubAck(packet) => packet.encode(buf),
156            Self::PingReq(packet) => packet.encode(buf),
157            Self::PingResp(packet) => packet.encode(buf),
158            Self::Disconnect(packet) => packet.encode(buf),
159            Self::Auth(packet) => packet.encode(buf),
160        }
161    }
162}