1use std::{fmt, num::NonZeroU16};
2
3use ntex_bytes::{ByteString, Bytes};
4
5use crate::types::{packet_type, QoS};
6
7prim_enum! {
8 pub enum ConnectAckReason {
10 ConnectionAccepted = 0,
12 UnacceptableProtocolVersion = 1,
14 IdentifierRejected = 2,
16 ServiceUnavailable = 3,
18 BadUserNameOrPassword = 4,
20 NotAuthorized = 5,
22 Reserved = 6
24 }
25}
26
27impl ConnectAckReason {
28 pub fn reason(self) -> &'static str {
29 match self {
30 ConnectAckReason::ConnectionAccepted => "Connection Accepted",
31 ConnectAckReason::UnacceptableProtocolVersion => {
32 "Connection Refused, unacceptable protocol version"
33 }
34 ConnectAckReason::IdentifierRejected => "Connection Refused, identifier rejected",
35 ConnectAckReason::ServiceUnavailable => "Connection Refused, Server unavailable",
36 ConnectAckReason::BadUserNameOrPassword => {
37 "Connection Refused, bad user name or password"
38 }
39 ConnectAckReason::NotAuthorized => "Connection Refused, not authorized",
40 _ => "Connection Refused",
41 }
42 }
43}
44
45#[derive(Debug, PartialEq, Eq, Clone)]
46pub struct LastWill {
48 pub qos: QoS,
50 pub retain: bool,
52 pub topic: ByteString,
54 pub message: Bytes,
56}
57
58#[derive(Default, Debug, PartialEq, Eq, Clone)]
59pub struct Connect {
61 pub clean_session: bool,
63 pub keep_alive: u16,
65 pub last_will: Option<LastWill>,
67 pub client_id: ByteString,
69 pub username: Option<ByteString>,
71 pub password: Option<Bytes>,
73}
74
75impl Connect {
76 pub fn client_id<T>(mut self, client_id: T) -> Self
78 where
79 ByteString: From<T>,
80 {
81 self.client_id = client_id.into();
82 self
83 }
84}
85
86#[derive(Debug, PartialEq, Eq, Clone)]
87pub struct Publish {
89 pub dup: bool,
91 pub retain: bool,
92 pub qos: QoS,
94 pub topic: ByteString,
96 pub packet_id: Option<NonZeroU16>,
98 pub payload_size: u32,
100}
101
102#[derive(Debug, PartialEq, Eq, Copy, Clone)]
103pub struct ConnectAck {
105 pub return_code: ConnectAckReason,
106 pub session_present: bool,
109}
110
111#[derive(Debug, PartialEq, Eq, Copy, Clone)]
112pub enum SubscribeReturnCode {
114 Success(QoS),
115 Failure,
116}
117
118#[derive(Debug, PartialEq, Eq, Clone)]
119pub enum Packet {
121 Connect(Box<Connect>),
123 ConnectAck(ConnectAck),
125 PublishAck {
127 packet_id: NonZeroU16,
129 },
130 PublishReceived {
132 packet_id: NonZeroU16,
134 },
135 PublishRelease {
137 packet_id: NonZeroU16,
139 },
140 PublishComplete {
142 packet_id: NonZeroU16,
144 },
145 Subscribe {
147 packet_id: NonZeroU16,
149 topic_filters: Vec<(ByteString, QoS)>,
151 },
152 SubscribeAck {
154 packet_id: NonZeroU16,
155 status: Vec<SubscribeReturnCode>,
157 },
158 Unsubscribe {
160 packet_id: NonZeroU16,
162 topic_filters: Vec<ByteString>,
164 },
165 UnsubscribeAck {
167 packet_id: NonZeroU16,
169 },
170 PingRequest,
172 PingResponse,
174 Disconnect,
176}
177
178impl From<Connect> for Packet {
179 fn from(val: Connect) -> Packet {
180 Packet::Connect(Box::new(val))
181 }
182}
183
184impl Packet {
185 pub fn packet_type(&self) -> u8 {
186 match self {
187 Packet::Connect(_) => packet_type::CONNECT,
188 Packet::ConnectAck { .. } => packet_type::CONNACK,
189 Packet::PublishAck { .. } => packet_type::PUBACK,
190 Packet::PublishReceived { .. } => packet_type::PUBREC,
191 Packet::PublishRelease { .. } => packet_type::PUBREL,
192 Packet::PublishComplete { .. } => packet_type::PUBCOMP,
193 Packet::Subscribe { .. } => packet_type::SUBSCRIBE,
194 Packet::SubscribeAck { .. } => packet_type::SUBACK,
195 Packet::Unsubscribe { .. } => packet_type::UNSUBSCRIBE,
196 Packet::UnsubscribeAck { .. } => packet_type::UNSUBACK,
197 Packet::PingRequest => packet_type::PINGREQ,
198 Packet::PingResponse => packet_type::PINGRESP,
199 Packet::Disconnect => packet_type::DISCONNECT,
200 }
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207
208 #[test]
209 fn test_ack_reason() {
210 assert_eq!(ConnectAckReason::ConnectionAccepted.reason(), "Connection Accepted");
211 assert_eq!(
212 ConnectAckReason::UnacceptableProtocolVersion.reason(),
213 "Connection Refused, unacceptable protocol version"
214 );
215 assert_eq!(
216 ConnectAckReason::IdentifierRejected.reason(),
217 "Connection Refused, identifier rejected"
218 );
219 assert_eq!(
220 ConnectAckReason::ServiceUnavailable.reason(),
221 "Connection Refused, Server unavailable"
222 );
223 assert_eq!(
224 ConnectAckReason::BadUserNameOrPassword.reason(),
225 "Connection Refused, bad user name or password"
226 );
227 assert_eq!(
228 ConnectAckReason::NotAuthorized.reason(),
229 "Connection Refused, not authorized"
230 );
231 }
232}