1use bytes::{Buf, BufMut, Bytes, BytesMut};
2use bytestring::ByteString;
3use serde::{Deserialize, Serialize};
4
5use crate::error::{DecodeError, EncodeError};
6use crate::utils::{self, Decode, Property};
7use crate::v5::{encode::*, property_type as pt, UserProperties, UserProperty};
8
9#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
11pub struct Disconnect {
12 pub reason_code: DisconnectReasonCode,
13 pub session_expiry_interval_secs: Option<u32>,
14 pub server_reference: Option<ByteString>,
15 pub reason_string: Option<ByteString>,
16 pub user_properties: UserProperties,
17}
18
19pub trait ToReasonCode {
21 fn to_reason_code(&self) -> DisconnectReasonCode;
22}
23
24prim_enum! {
25 #[derive(Deserialize, Serialize)]
27 pub enum DisconnectReasonCode {
28 NormalDisconnection = 0,
29 DisconnectWithWillMessage = 4,
30 UnspecifiedError = 128,
31 MalformedPacket = 129,
32 ProtocolError = 130,
33 ImplementationSpecificError = 131,
34 NotAuthorized = 135,
35 ServerBusy = 137,
36 ServerShuttingDown = 139,
37 BadAuthenticationMethod = 140,
38 KeepAliveTimeout = 141,
39 SessionTakenOver = 142,
40 TopicFilterInvalid = 143,
41 TopicNameInvalid = 144,
42 ReceiveMaximumExceeded = 147,
43 TopicAliasInvalid = 148,
44 PacketTooLarge = 149,
45 MessageRateTooHigh = 150,
46 QuotaExceeded = 151,
47 AdministrativeAction = 152,
48 PayloadFormatInvalid = 153,
49 RetainNotSupported = 154,
50 QosNotSupported = 155,
51 UseAnotherServer = 156,
52 ServerMoved = 157,
53 SharedSubscriptionNotSupported = 158,
54 ConnectionRateExceeded = 159,
55 MaximumConnectTime = 160,
56 SubscriptionIdentifiersNotSupported = 161,
57 WildcardSubscriptionsNotSupported = 162
58 }
59}
60
61impl From<DisconnectReasonCode> for u8 {
62 fn from(v: DisconnectReasonCode) -> Self {
63 match v {
64 DisconnectReasonCode::NormalDisconnection => 0,
65 DisconnectReasonCode::DisconnectWithWillMessage => 4,
66 DisconnectReasonCode::UnspecifiedError => 128,
67 DisconnectReasonCode::MalformedPacket => 129,
68 DisconnectReasonCode::ProtocolError => 130,
69 DisconnectReasonCode::ImplementationSpecificError => 131,
70 DisconnectReasonCode::NotAuthorized => 135,
71 DisconnectReasonCode::ServerBusy => 137,
72 DisconnectReasonCode::ServerShuttingDown => 139,
73 DisconnectReasonCode::BadAuthenticationMethod => 140,
74 DisconnectReasonCode::KeepAliveTimeout => 141,
75 DisconnectReasonCode::SessionTakenOver => 142,
76 DisconnectReasonCode::TopicFilterInvalid => 143,
77 DisconnectReasonCode::TopicNameInvalid => 144,
78 DisconnectReasonCode::ReceiveMaximumExceeded => 147,
79 DisconnectReasonCode::TopicAliasInvalid => 148,
80 DisconnectReasonCode::PacketTooLarge => 149,
81 DisconnectReasonCode::MessageRateTooHigh => 150,
82 DisconnectReasonCode::QuotaExceeded => 151,
83 DisconnectReasonCode::AdministrativeAction => 152,
84 DisconnectReasonCode::PayloadFormatInvalid => 153,
85 DisconnectReasonCode::RetainNotSupported => 154,
86 DisconnectReasonCode::QosNotSupported => 155,
87 DisconnectReasonCode::UseAnotherServer => 156,
88 DisconnectReasonCode::ServerMoved => 157,
89 DisconnectReasonCode::SharedSubscriptionNotSupported => 158,
90 DisconnectReasonCode::ConnectionRateExceeded => 159,
91 DisconnectReasonCode::MaximumConnectTime => 160,
92 DisconnectReasonCode::SubscriptionIdentifiersNotSupported => 161,
93 DisconnectReasonCode::WildcardSubscriptionsNotSupported => 162,
94 }
95 }
96}
97
98impl Disconnect {
99 pub fn new(reason_code: DisconnectReasonCode) -> Self {
101 Self {
102 reason_code,
103 session_expiry_interval_secs: None,
104 server_reference: None,
105 reason_string: None,
106 user_properties: Vec::new(),
107 }
108 }
109
110 pub(crate) fn decode(src: &mut Bytes) -> Result<Self, DecodeError> {
111 let disconnect = if src.has_remaining() {
112 let reason_code = src.get_u8().try_into()?;
113
114 if src.has_remaining() {
115 let mut session_exp_secs = None;
116 let mut server_reference = None;
117 let mut reason_string = None;
118 let mut user_properties = Vec::new();
119
120 let prop_src = &mut utils::take_properties(src)?;
121 while prop_src.has_remaining() {
122 match prop_src.get_u8() {
123 pt::SESS_EXPIRY_INT => session_exp_secs.read_value(prop_src)?,
124 pt::REASON_STRING => reason_string.read_value(prop_src)?,
125 pt::USER => user_properties.push(UserProperty::decode(prop_src)?),
126 pt::SERVER_REF => server_reference.read_value(prop_src)?,
127 _ => return Err(DecodeError::MalformedPacket),
128 }
129 }
130 ensure!(!src.has_remaining(), DecodeError::InvalidLength);
131
132 Self {
133 reason_code,
134 session_expiry_interval_secs: session_exp_secs,
135 server_reference,
136 reason_string,
137 user_properties,
138 }
139 } else {
140 Self { reason_code, ..Default::default() }
141 }
142 } else {
143 Self::default()
144 };
145 Ok(disconnect)
146 }
147}
148
149impl Default for Disconnect {
150 fn default() -> Self {
151 Self {
152 reason_code: DisconnectReasonCode::NormalDisconnection,
153 session_expiry_interval_secs: None,
154 server_reference: None,
155 reason_string: None,
156 user_properties: Vec::new(),
157 }
158 }
159}
160
161impl EncodeLtd for Disconnect {
162 fn encoded_size(&self, limit: u32) -> usize {
163 const HEADER_LEN: usize = 1; let mut prop_len = encoded_property_size(&self.session_expiry_interval_secs)
166 + encoded_property_size(&self.server_reference);
167 let diag_len = encoded_size_opt_props(
168 &self.user_properties,
169 &self.reason_string,
170 reduce_limit(limit, prop_len + HEADER_LEN + 4),
171 ); prop_len += diag_len;
173 HEADER_LEN + var_int_len(prop_len) as usize + prop_len
174 }
175
176 fn encode(&self, buf: &mut BytesMut, size: u32) -> Result<(), EncodeError> {
177 let start_len = buf.len();
178 buf.put_u8(self.reason_code.into());
179
180 let prop_len = var_int_len_from_size(size - 1);
181 utils::write_variable_length(prop_len, buf);
182 encode_property(&self.session_expiry_interval_secs, pt::SESS_EXPIRY_INT, buf)?;
183 encode_property(&self.server_reference, pt::SERVER_REF, buf)?;
184 encode_opt_props(
185 &self.user_properties,
186 &self.reason_string,
187 buf,
188 size - (buf.len() - start_len) as u32,
189 )
190 }
191}