mod properties;
pub use properties::ConnAckProperties;
mod reason_code;
pub use reason_code::ConnAckReasonCode;
use super::{
VariableInteger,
error::{DeserializeError, SerializeError},
mqtt_trait::{MqttAsyncRead, MqttRead, MqttWrite, PacketAsyncRead, PacketRead, PacketWrite, WireLength},
};
use bytes::{Buf, BufMut};
use tokio::io::AsyncReadExt;
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct ConnAck {
pub connack_flags: ConnAckFlags,
pub reason_code: ConnAckReasonCode,
pub connack_properties: ConnAckProperties,
}
impl PacketRead for ConnAck {
fn read(_: u8, header_len: usize, mut buf: bytes::Bytes) -> Result<Self, DeserializeError> {
if header_len > buf.len() {
return Err(DeserializeError::InsufficientData(std::any::type_name::<Self>(), buf.len(), header_len));
}
let connack_flags = ConnAckFlags::read(&mut buf)?;
let reason_code = ConnAckReasonCode::read(&mut buf)?;
let connack_properties = ConnAckProperties::read(&mut buf)?;
Ok(Self {
connack_flags,
reason_code,
connack_properties,
})
}
}
impl<S> PacketAsyncRead<S> for ConnAck
where
S: tokio::io::AsyncRead + Unpin,
{
async fn async_read(_: u8, _: usize, stream: &mut S) -> Result<(Self, usize), super::error::ReadError> {
let (connack_flags, read_bytes) = ConnAckFlags::async_read(stream).await?;
let (reason_code, reason_code_read_bytes) = ConnAckReasonCode::async_read(stream).await?;
let (connack_properties, connack_properties_read_bytes) = ConnAckProperties::async_read(stream).await?;
Ok((
Self {
connack_flags,
reason_code,
connack_properties,
},
read_bytes + reason_code_read_bytes + connack_properties_read_bytes,
))
}
}
impl PacketWrite for ConnAck {
fn write(&self, buf: &mut bytes::BytesMut) -> Result<(), SerializeError> {
self.connack_flags.write(buf)?;
self.reason_code.write(buf)?;
self.connack_properties.write(buf)?;
Ok(())
}
}
impl<S> crate::packets::mqtt_trait::PacketAsyncWrite<S> for ConnAck
where
S: tokio::io::AsyncWrite + Unpin,
{
async fn async_write(&self, stream: &mut S) -> Result<usize, crate::packets::error::WriteError> {
use crate::packets::mqtt_trait::MqttAsyncWrite;
let connack_flags_written = self.connack_flags.async_write(stream).await?;
let reason_code_written = self.reason_code.async_write(stream).await?;
let connack_properties_written = self.connack_properties.async_write(stream).await?;
Ok(connack_flags_written + reason_code_written + connack_properties_written)
}
}
impl WireLength for ConnAck {
fn wire_len(&self) -> usize {
2 + self.connack_properties.wire_len().variable_integer_len() +
self.connack_properties.wire_len()
}
}
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
pub struct ConnAckFlags {
pub session_present: bool,
}
impl<S> MqttAsyncRead<S> for ConnAckFlags
where
S: tokio::io::AsyncRead + Unpin,
{
async fn async_read(stream: &mut S) -> Result<(Self, usize), super::error::ReadError> {
let byte = stream.read_u8().await?;
Ok((
Self {
session_present: (byte & 0b00000001) == 0b00000001,
},
1,
))
}
}
impl MqttRead for ConnAckFlags {
fn read(buf: &mut bytes::Bytes) -> Result<Self, DeserializeError> {
if buf.is_empty() {
return Err(DeserializeError::InsufficientData(std::any::type_name::<Self>(), 0, 1));
}
let byte = buf.get_u8();
Ok(Self {
session_present: (byte & 0b00000001) == 0b00000001,
})
}
}
impl MqttWrite for ConnAckFlags {
fn write(&self, buf: &mut bytes::BytesMut) -> Result<(), super::error::SerializeError> {
let byte = self.session_present as u8;
buf.put_u8(byte);
Ok(())
}
}
impl<S> crate::packets::mqtt_trait::MqttAsyncWrite<S> for ConnAckFlags
where
S: tokio::io::AsyncWrite + Unpin,
{
async fn async_write(&self, stream: &mut S) -> Result<usize, crate::packets::error::WriteError> {
use tokio::io::AsyncWriteExt;
let byte = self.session_present as u8;
stream.write_u8(byte).await?;
Ok(1)
}
}
#[cfg(test)]
mod tests {
use crate::packets::{
ConnAckReasonCode, Packet, VariableInteger,
connack::{ConnAck, ConnAckProperties},
mqtt_trait::{MqttRead, MqttWrite, PacketRead, PacketWrite, WireLength},
};
#[test]
fn test_wire_len() {
let mut buf = bytes::BytesMut::new();
let connack_properties = ConnAckProperties {
session_expiry_interval: Some(60), receive_maximum: Some(20), maximum_qos: Some(crate::packets::QoS::AtMostOnce), retain_available: Some(true), maximum_packet_size: Some(1024), assigned_client_identifier: Some(Box::from("client-12345")), topic_alias_maximum: Some(10), reason_string: Some(Box::from("Connection accepted")), user_properties: vec![(Box::from("key1"), Box::from("value1"))], wildcards_available: Some(true), subscription_ids_available: Some(true), shared_subscription_available: Some(true), server_keep_alive: Some(120), response_info: Some(Box::from("Response info")), server_reference: Some(Box::from("server-reference")), authentication_method: Some(Box::from("auth-method")), authentication_data: Some(vec![1, 2, 3, 4]), };
let len = connack_properties.wire_len();
let len_of_wire_len = len.write_variable_integer(&mut buf).unwrap();
buf.clear();
connack_properties.write(&mut buf).unwrap();
assert_eq!(len + len_of_wire_len, buf.len());
}
#[test]
fn read_write_connack_packet() {
let c = ConnAck { ..Default::default() };
let p1 = Packet::ConnAck(c);
let mut buf = bytes::BytesMut::new();
p1.write(&mut buf).unwrap();
let p2 = Packet::read(&mut buf).unwrap();
assert_eq!(p1, p2);
}
#[test]
fn read_write_connack() {
let mut buf = bytes::BytesMut::new();
let packet = &[
0x01, 0x00, 0x00, ];
buf.extend_from_slice(packet);
let c1 = ConnAck::read(0, packet.len(), buf.into()).unwrap();
assert_eq!(ConnAckReasonCode::Success, c1.reason_code);
assert_eq!(ConnAckProperties::default(), c1.connack_properties);
let mut buf = bytes::BytesMut::new();
c1.write(&mut buf).unwrap();
let c2 = ConnAck::read(0, packet.len(), buf.into()).unwrap();
assert_eq!(c1, c2)
}
#[test]
fn read_write_connack_properties() {
let mut buf = bytes::BytesMut::new();
let packet = &[
56, 17, 0xff, 0xff, 37, 0x1, 18, 0, 11, b'K', b'e', b'a', b'n', b'u', b'R', b'e', b'e', b'v', b'e', b's', 36, 2, 34, 0, 255, 31, 0, 29, b'H', b'o', b'u', b's', b't', b'o', b'n', b' ', b'w', b'e', b' ', b'h', b'a', b'v', b'e', b' ', b'g', b'o', b't', b' ', b'a', b' ', b'p', b'r', b'o', b'b', b'l', b'e', b'm',
];
buf.extend_from_slice(packet);
let c1 = ConnAckProperties::read(&mut buf.into()).unwrap();
let mut buf = bytes::BytesMut::new();
let variable_length = c1.wire_len();
assert_eq!(variable_length, 56);
c1.write(&mut buf).unwrap();
let _buf_clone = buf.to_vec();
let c2 = ConnAckProperties::read(&mut buf.into()).unwrap();
assert_eq!(c1, c2);
}
}