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 {
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 pub cert: Option<CertInfo>,
92}
93
94impl Connect {
95 pub fn client_id<T>(mut self, client_id: T) -> Self
97 where
98 ByteString: From<T>,
99 {
100 self.client_id = client_id.into();
101 self
102 }
103}
104
105pub(crate) type Publish = crate::types::Publish;
106
107#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
108pub struct ConnectAck {
110 pub return_code: ConnectAckReason,
111 pub session_present: bool,
114}
115
116#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize)]
117pub enum SubscribeReturnCode {
119 Success(QoS),
120 Failure,
121}
122
123#[derive(Debug, PartialEq, Eq, Clone)]
124pub enum Packet {
126 Connect(Box<Connect>),
128
129 ConnectAck(ConnectAck),
131
132 Publish(Box<Publish>),
134
135 PublishAck {
137 packet_id: NonZeroU16,
139 },
140 PublishReceived {
142 packet_id: NonZeroU16,
144 },
145 PublishRelease {
147 packet_id: NonZeroU16,
149 },
150 PublishComplete {
152 packet_id: NonZeroU16,
154 },
155
156 Subscribe {
158 packet_id: NonZeroU16,
160 topic_filters: Vec<(ByteString, QoS)>,
162 },
163 SubscribeAck {
165 packet_id: NonZeroU16,
166 status: Vec<SubscribeReturnCode>,
168 },
169
170 Unsubscribe {
172 packet_id: NonZeroU16,
174 topic_filters: Vec<ByteString>,
176 },
177 UnsubscribeAck {
179 packet_id: NonZeroU16,
181 },
182
183 PingRequest,
185 PingResponse,
187 Disconnect,
189}
190
191impl From<Connect> for Packet {
192 fn from(val: Connect) -> Packet {
193 Packet::Connect(Box::new(val))
194 }
195}
196
197impl From<Publish> for Packet {
198 fn from(val: Publish) -> Packet {
199 Packet::Publish(Box::new(val))
200 }
201}
202
203impl Packet {
204 pub fn packet_type(&self) -> u8 {
205 match self {
206 Packet::Connect(_) => packet_type::CONNECT,
207 Packet::ConnectAck { .. } => packet_type::CONNACK,
208 Packet::Publish(_) => packet_type::PUBLISH_START,
209 Packet::PublishAck { .. } => packet_type::PUBACK,
210 Packet::PublishReceived { .. } => packet_type::PUBREC,
211 Packet::PublishRelease { .. } => packet_type::PUBREL,
212 Packet::PublishComplete { .. } => packet_type::PUBCOMP,
213 Packet::Subscribe { .. } => packet_type::SUBSCRIBE,
214 Packet::SubscribeAck { .. } => packet_type::SUBACK,
215 Packet::Unsubscribe { .. } => packet_type::UNSUBSCRIBE,
216 Packet::UnsubscribeAck { .. } => packet_type::UNSUBACK,
217 Packet::PingRequest => packet_type::PINGREQ,
218 Packet::PingResponse => packet_type::PINGRESP,
219 Packet::Disconnect => packet_type::DISCONNECT,
220 }
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227
228 #[test]
229 fn test_ack_reason() {
230 assert_eq!(ConnectAckReason::ConnectionAccepted.reason(), "Connection Accepted");
231 assert_eq!(
232 ConnectAckReason::UnacceptableProtocolVersion.reason(),
233 "Connection Refused, unacceptable protocol version"
234 );
235 assert_eq!(ConnectAckReason::IdentifierRejected.reason(), "Connection Refused, identifier rejected");
236 assert_eq!(ConnectAckReason::ServiceUnavailable.reason(), "Connection Refused, Server unavailable");
237 assert_eq!(
238 ConnectAckReason::BadUserNameOrPassword.reason(),
239 "Connection Refused, bad user name or password"
240 );
241 assert_eq!(ConnectAckReason::NotAuthorized.reason(), "Connection Refused, not authorized");
242 }
243}