mqute_codec/protocol/v3/
connack.rs

1//! # ConnAck Packet V3
2//!
3//! This module defines the `ConnAck` packet, which is used in the MQTT protocol to acknowledge
4//! a connection request from a client. The `ConnAck` packet contains a `ConnectReturnCode` that
5//! indicates the result of the connection attempt.
6
7use crate::Error;
8use crate::codec::util::decode_byte;
9use crate::codec::{Decode, Encode, RawPacket};
10use crate::protocol::v4::ConnectReturnCode;
11use crate::protocol::{FixedHeader, PacketType, traits};
12use bytes::{Buf, BufMut, BytesMut};
13
14/// Represents an MQTT `ConnAck` packet.
15///
16/// The `ConnAck` packet is sent by the server to the client in response to a `Connect` request.
17/// It contains a `ConnectReturnCode` that indicates the result of the connection attempt.
18///
19/// # Examples
20///
21/// ```rust
22/// use mqute_codec::protocol::v4::ConnectReturnCode;
23/// use mqute_codec::protocol::v3::ConnAck;
24///
25/// let connack = ConnAck::new(ConnectReturnCode::Success);
26/// let code = connack.code();
27/// assert_eq!(code, ConnectReturnCode::Success);
28/// ```
29#[derive(Debug, Copy, Clone, PartialEq, Eq)]
30pub struct ConnAck(ConnectReturnCode);
31
32impl ConnAck {
33    /// Creates a new `ConnAck` packet with the specified return code.
34    pub fn new(code: ConnectReturnCode) -> Self {
35        ConnAck(code)
36    }
37
38    /// Returns the `ConnectReturnCode` contained in the `ConnAck` packet.
39    pub fn code(&self) -> ConnectReturnCode {
40        self.0
41    }
42}
43
44impl Decode for ConnAck {
45    fn decode(mut packet: RawPacket) -> Result<Self, Error> {
46        if packet.header.packet_type() != PacketType::ConnAck || !packet.header.flags().is_default()
47        {
48            return Err(Error::MalformedPacket);
49        }
50
51        // Skip the unused byte
52        packet.payload.advance(1);
53
54        let ret_code = decode_byte(&mut packet.payload)?;
55        let code = ret_code.try_into()?;
56
57        Ok(ConnAck(code))
58    }
59}
60
61impl Encode for ConnAck {
62    fn encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
63        let header = FixedHeader::new(PacketType::ConnAck, self.payload_len());
64        header.encode(buf)?;
65
66        // Write a zero byte (reserved byte in ConnAck)
67        buf.put_u8(0);
68
69        // Write the connect return code
70        buf.put_u8(self.0.into());
71        Ok(())
72    }
73
74    fn payload_len(&self) -> usize {
75        // The payload length for a `ConnAck` packet is always 2 bytes:
76        // 1 byte for the reserved byte.
77        // 1 byte for the return code.
78        2
79    }
80}
81
82impl traits::ConnAck for ConnAck {}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87    use crate::codec::PacketCodec;
88    use bytes::BytesMut;
89    use tokio_util::codec::Decoder;
90
91    #[test]
92    fn connack_decode() {
93        let mut codec = PacketCodec::new(None, None);
94
95        let data = &[
96            (PacketType::ConnAck as u8) << 4, // Packet type
97            0x02,                             // Remaining len
98            0x00,                             // Connect Acknowledge Flags
99            0x00,                             // Connect Return code
100        ];
101
102        let mut stream = BytesMut::new();
103
104        stream.extend_from_slice(&data[..]);
105
106        let raw_packet = codec.decode(&mut stream).unwrap().unwrap();
107        let packet = ConnAck::decode(raw_packet).unwrap();
108
109        assert_eq!(packet, ConnAck::new(ConnectReturnCode::Success));
110    }
111
112    #[test]
113    fn connack_encode() {
114        let packet = ConnAck::new(ConnectReturnCode::Success);
115
116        let mut stream = BytesMut::new();
117        packet.encode(&mut stream).unwrap();
118        assert_eq!(
119            stream,
120            vec![(PacketType::ConnAck as u8) << 4, 0x02, 0x00, 0x00]
121        );
122    }
123}