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::codec::util::decode_byte;
8use crate::codec::{Decode, Encode, RawPacket};
9use crate::protocol::v4::ConnectReturnCode;
10use crate::protocol::{FixedHeader, PacketType};
11use crate::Error;
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
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use crate::codec::PacketCodec;
86    use bytes::BytesMut;
87    use tokio_util::codec::Decoder;
88
89    #[test]
90    fn connack_decode() {
91        let mut codec = PacketCodec::new(None, None);
92
93        let data = &[
94            (PacketType::ConnAck as u8) << 4, // Packet type
95            0x02,                             // Remaining len
96            0x00,                             // Connect Acknowledge Flags
97            0x00,                             // Connect Return code
98        ];
99
100        let mut stream = BytesMut::new();
101
102        stream.extend_from_slice(&data[..]);
103
104        let raw_packet = codec.decode(&mut stream).unwrap().unwrap();
105        let packet = ConnAck::decode(raw_packet).unwrap();
106
107        assert_eq!(packet, ConnAck::new(ConnectReturnCode::Success));
108    }
109
110    #[test]
111    fn connack_encode() {
112        let packet = ConnAck::new(ConnectReturnCode::Success);
113
114        let mut stream = BytesMut::new();
115        packet.encode(&mut stream).unwrap();
116        assert_eq!(
117            stream,
118            vec![(PacketType::ConnAck as u8) << 4, 0x02, 0x00, 0x00]
119        );
120    }
121}