1use std::num::NonZeroU16;
2
3use bytes::Bytes;
4use bytestring::ByteString;
5use serde::{Deserialize, Serialize};
6
7use crate::types::{packet_type, Protocol, QoS};
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 {
46 match self {
47 ConnectAckReason::ConnectionAccepted => "Connection Accepted",
48 ConnectAckReason::UnacceptableProtocolVersion => {
49 "Connection Refused, unacceptable protocol version"
50 }
51 ConnectAckReason::IdentifierRejected => "Connection Refused, identifier rejected",
52 ConnectAckReason::ServiceUnavailable => "Connection Refused, Server unavailable",
53 ConnectAckReason::BadUserNameOrPassword => "Connection Refused, bad user name or password",
54 ConnectAckReason::NotAuthorized => "Connection Refused, not authorized",
55 _ => "Connection Refused",
56 }
57 }
58}
59
60#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
61pub struct LastWill {
63 pub qos: QoS,
65 pub retain: bool,
67 pub topic: ByteString,
69 pub message: Bytes,
71}
72
73#[derive(Default, Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
74pub struct Connect {
76 pub protocol: Protocol,
78 pub clean_session: bool,
80 pub keep_alive: u16,
82 pub last_will: Option<LastWill>,
84 pub client_id: ByteString,
86 pub username: Option<ByteString>,
88 pub password: Option<Bytes>,
90}
91
92impl Connect {
93 pub fn client_id<T>(mut self, client_id: T) -> Self
95 where
96 ByteString: From<T>,
97 {
98 self.client_id = client_id.into();
99 self
100 }
101}
102
103pub(crate) type Publish = crate::types::Publish;
104
105#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
106pub struct ConnectAck {
108 pub return_code: ConnectAckReason,
109 pub session_present: bool,
112}
113
114#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
115pub enum SubscribeReturnCode {
117 Success(QoS),
118 Failure,
119}
120
121#[derive(Debug, PartialEq, Eq, Clone)]
122pub enum Packet {
124 Connect(Box<Connect>),
126
127 ConnectAck(ConnectAck),
129
130 Publish(Box<Publish>),
132
133 PublishAck {
135 packet_id: NonZeroU16,
137 },
138 PublishReceived {
140 packet_id: NonZeroU16,
142 },
143 PublishRelease {
145 packet_id: NonZeroU16,
147 },
148 PublishComplete {
150 packet_id: NonZeroU16,
152 },
153
154 Subscribe {
156 packet_id: NonZeroU16,
158 topic_filters: Vec<(ByteString, QoS)>,
160 },
161 SubscribeAck {
163 packet_id: NonZeroU16,
164 status: Vec<SubscribeReturnCode>,
166 },
167
168 Unsubscribe {
170 packet_id: NonZeroU16,
172 topic_filters: Vec<ByteString>,
174 },
175 UnsubscribeAck {
177 packet_id: NonZeroU16,
179 },
180
181 PingRequest,
183 PingResponse,
185 Disconnect,
187}
188
189impl From<Connect> for Packet {
190 fn from(val: Connect) -> Packet {
191 Packet::Connect(Box::new(val))
192 }
193}
194
195impl From<Publish> for Packet {
196 fn from(val: Publish) -> Packet {
197 Packet::Publish(Box::new(val))
198 }
199}
200
201impl Packet {
202 pub fn packet_type(&self) -> u8 {
203 match self {
204 Packet::Connect(_) => packet_type::CONNECT,
205 Packet::ConnectAck { .. } => packet_type::CONNACK,
206 Packet::Publish(_) => packet_type::PUBLISH_START,
207 Packet::PublishAck { .. } => packet_type::PUBACK,
208 Packet::PublishReceived { .. } => packet_type::PUBREC,
209 Packet::PublishRelease { .. } => packet_type::PUBREL,
210 Packet::PublishComplete { .. } => packet_type::PUBCOMP,
211 Packet::Subscribe { .. } => packet_type::SUBSCRIBE,
212 Packet::SubscribeAck { .. } => packet_type::SUBACK,
213 Packet::Unsubscribe { .. } => packet_type::UNSUBSCRIBE,
214 Packet::UnsubscribeAck { .. } => packet_type::UNSUBACK,
215 Packet::PingRequest => packet_type::PINGREQ,
216 Packet::PingResponse => packet_type::PINGRESP,
217 Packet::Disconnect => packet_type::DISCONNECT,
218 }
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225
226 #[test]
227 fn test_ack_reason() {
228 assert_eq!(ConnectAckReason::ConnectionAccepted.reason(), "Connection Accepted");
229 assert_eq!(
230 ConnectAckReason::UnacceptableProtocolVersion.reason(),
231 "Connection Refused, unacceptable protocol version"
232 );
233 assert_eq!(ConnectAckReason::IdentifierRejected.reason(), "Connection Refused, identifier rejected");
234 assert_eq!(ConnectAckReason::ServiceUnavailable.reason(), "Connection Refused, Server unavailable");
235 assert_eq!(
236 ConnectAckReason::BadUserNameOrPassword.reason(),
237 "Connection Refused, bad user name or password"
238 );
239 assert_eq!(ConnectAckReason::NotAuthorized.reason(), "Connection Refused, not authorized");
240 }
241}