1use std::num::NonZeroU16;
2
3use crate::cert::CertInfo;
4use crate::types::{packet_type, Protocol, QoS};
5use bytes::Bytes;
6use bytestring::ByteString;
7use serde::{Deserialize, Serialize};
8
9prim_enum! {
10 #[derive(Deserialize, Serialize)]
12 pub enum ConnectAckReason {
13 ConnectionAccepted = 0,
15 UnacceptableProtocolVersion = 1,
17 IdentifierRejected = 2,
19 ServiceUnavailable = 3,
21 BadUserNameOrPassword = 4,
23 NotAuthorized = 5,
25 Reserved = 6
27 }
28}
29
30impl From<ConnectAckReason> for u8 {
31 fn from(v: ConnectAckReason) -> Self {
32 match v {
33 ConnectAckReason::ConnectionAccepted => 0,
34 ConnectAckReason::UnacceptableProtocolVersion => 1,
35 ConnectAckReason::IdentifierRejected => 2,
36 ConnectAckReason::ServiceUnavailable => 3,
37 ConnectAckReason::BadUserNameOrPassword => 4,
38 ConnectAckReason::NotAuthorized => 5,
39 ConnectAckReason::Reserved => 6,
40 }
41 }
42}
43
44impl ConnectAckReason {
45 pub fn reason(self) -> &'static str {
47 match self {
48 ConnectAckReason::ConnectionAccepted => "Connection Accepted",
49 ConnectAckReason::UnacceptableProtocolVersion => {
50 "Connection Refused, unacceptable protocol version"
51 }
52 ConnectAckReason::IdentifierRejected => "Connection Refused, identifier rejected",
53 ConnectAckReason::ServiceUnavailable => "Connection Refused, Server unavailable",
54 ConnectAckReason::BadUserNameOrPassword => "Connection Refused, bad user name or password",
55 ConnectAckReason::NotAuthorized => "Connection Refused, not authorized",
56 _ => "Connection Refused",
57 }
58 }
59}
60
61#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
62pub struct LastWill {
64 pub qos: QoS,
66 pub retain: bool,
68 pub topic: ByteString,
70 pub message: Bytes,
72}
73
74#[derive(Default, Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
75pub struct Connect {
77 pub protocol: Protocol,
79 pub clean_session: bool,
81 pub keep_alive: u16,
83 pub last_will: Option<LastWill>,
85 pub client_id: ByteString,
87 pub username: Option<ByteString>,
89 pub password: Option<Bytes>,
91 pub cert: Option<CertInfo>,
93}
94
95impl Connect {
96 pub fn client_id<T>(mut self, client_id: T) -> Self
98 where
99 ByteString: From<T>,
100 {
101 self.client_id = client_id.into();
102 self
103 }
104}
105
106pub(crate) type Publish = crate::types::Publish;
107
108#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
109pub struct ConnectAck {
111 pub return_code: ConnectAckReason,
112 pub session_present: bool,
115}
116
117#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
118pub enum SubscribeReturnCode {
120 Success(QoS),
121 Failure,
122}
123
124#[derive(Debug, PartialEq, Eq, Clone)]
125pub enum Packet {
127 Connect(Box<Connect>),
129
130 ConnectAck(ConnectAck),
132
133 Publish(Box<Publish>),
135
136 PublishAck {
138 packet_id: NonZeroU16,
140 },
141 PublishReceived {
143 packet_id: NonZeroU16,
145 },
146 PublishRelease {
148 packet_id: NonZeroU16,
150 },
151 PublishComplete {
153 packet_id: NonZeroU16,
155 },
156
157 Subscribe {
159 packet_id: NonZeroU16,
161 topic_filters: Vec<(ByteString, QoS)>,
163 },
164 SubscribeAck {
166 packet_id: NonZeroU16,
167 status: Vec<SubscribeReturnCode>,
169 },
170
171 Unsubscribe {
173 packet_id: NonZeroU16,
175 topic_filters: Vec<ByteString>,
177 },
178 UnsubscribeAck {
180 packet_id: NonZeroU16,
182 },
183
184 PingRequest,
186 PingResponse,
188 Disconnect,
190}
191
192impl From<Connect> for Packet {
193 fn from(val: Connect) -> Packet {
194 Packet::Connect(Box::new(val))
195 }
196}
197
198impl From<Publish> for Packet {
199 fn from(val: Publish) -> Packet {
200 Packet::Publish(Box::new(val))
201 }
202}
203
204impl Packet {
205 pub fn packet_type(&self) -> u8 {
207 match self {
208 Packet::Connect(_) => packet_type::CONNECT,
209 Packet::ConnectAck { .. } => packet_type::CONNACK,
210 Packet::Publish(_) => packet_type::PUBLISH_START,
211 Packet::PublishAck { .. } => packet_type::PUBACK,
212 Packet::PublishReceived { .. } => packet_type::PUBREC,
213 Packet::PublishRelease { .. } => packet_type::PUBREL,
214 Packet::PublishComplete { .. } => packet_type::PUBCOMP,
215 Packet::Subscribe { .. } => packet_type::SUBSCRIBE,
216 Packet::SubscribeAck { .. } => packet_type::SUBACK,
217 Packet::Unsubscribe { .. } => packet_type::UNSUBSCRIBE,
218 Packet::UnsubscribeAck { .. } => packet_type::UNSUBACK,
219 Packet::PingRequest => packet_type::PINGREQ,
220 Packet::PingResponse => packet_type::PINGRESP,
221 Packet::Disconnect => packet_type::DISCONNECT,
222 }
223 }
224}
225
226#[cfg(test)]
227mod tests {
228 use super::*;
229
230 #[test]
231 fn test_ack_reason() {
232 assert_eq!(ConnectAckReason::ConnectionAccepted.reason(), "Connection Accepted");
233 assert_eq!(
234 ConnectAckReason::UnacceptableProtocolVersion.reason(),
235 "Connection Refused, unacceptable protocol version"
236 );
237 assert_eq!(ConnectAckReason::IdentifierRejected.reason(), "Connection Refused, identifier rejected");
238 assert_eq!(ConnectAckReason::ServiceUnavailable.reason(), "Connection Refused, Server unavailable");
239 assert_eq!(
240 ConnectAckReason::BadUserNameOrPassword.reason(),
241 "Connection Refused, bad user name or password"
242 );
243 assert_eq!(ConnectAckReason::NotAuthorized.reason(), "Connection Refused, not authorized");
244 }
245}