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(Duration::from_secs(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}