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