1use std::num::NonZeroU16;
2
3use ntex_bytes::{ByteString, Bytes};
4
5use crate::types::{QoS, packet_type};
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 ConnectAckReason::Reserved => "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 #[must_use]
77 pub fn client_id<T>(mut self, client_id: T) -> Self
79 where
80 ByteString: From<T>,
81 {
82 self.client_id = client_id.into();
83 self
84 }
85}
86
87#[derive(Debug, PartialEq, Eq, Clone)]
88pub struct Publish {
90 pub dup: bool,
92 pub retain: bool,
93 pub qos: QoS,
95 pub topic: ByteString,
97 pub packet_id: Option<NonZeroU16>,
99 pub payload_size: u32,
101}
102
103#[derive(Debug, PartialEq, Eq, Copy, Clone)]
104pub struct ConnectAck {
106 pub return_code: ConnectAckReason,
107 pub session_present: bool,
110}
111
112#[derive(Debug, PartialEq, Eq, Copy, Clone)]
113pub enum SubscribeReturnCode {
115 Success(QoS),
116 Failure,
117}
118
119#[derive(Debug, PartialEq, Eq, Clone)]
120pub enum Packet {
122 Connect(Box<Connect>),
124 ConnectAck(ConnectAck),
126 PublishAck {
128 packet_id: NonZeroU16,
130 },
131 PublishReceived {
133 packet_id: NonZeroU16,
135 },
136 PublishRelease {
138 packet_id: NonZeroU16,
140 },
141 PublishComplete {
143 packet_id: NonZeroU16,
145 },
146 Subscribe {
148 packet_id: NonZeroU16,
150 topic_filters: Vec<(ByteString, QoS)>,
152 },
153 SubscribeAck {
155 packet_id: NonZeroU16,
156 status: Vec<SubscribeReturnCode>,
158 },
159 Unsubscribe {
161 packet_id: NonZeroU16,
163 topic_filters: Vec<ByteString>,
165 },
166 UnsubscribeAck {
168 packet_id: NonZeroU16,
170 },
171 PingRequest,
173 PingResponse,
175 Disconnect,
177}
178
179impl From<Connect> for Packet {
180 fn from(val: Connect) -> Packet {
181 Packet::Connect(Box::new(val))
182 }
183}
184
185impl Packet {
186 pub fn packet_type(&self) -> u8 {
187 match self {
188 Packet::Connect(_) => packet_type::CONNECT,
189 Packet::ConnectAck { .. } => packet_type::CONNACK,
190 Packet::PublishAck { .. } => packet_type::PUBACK,
191 Packet::PublishReceived { .. } => packet_type::PUBREC,
192 Packet::PublishRelease { .. } => packet_type::PUBREL,
193 Packet::PublishComplete { .. } => packet_type::PUBCOMP,
194 Packet::Subscribe { .. } => packet_type::SUBSCRIBE,
195 Packet::SubscribeAck { .. } => packet_type::SUBACK,
196 Packet::Unsubscribe { .. } => packet_type::UNSUBSCRIBE,
197 Packet::UnsubscribeAck { .. } => packet_type::UNSUBACK,
198 Packet::PingRequest => packet_type::PINGREQ,
199 Packet::PingResponse => packet_type::PINGRESP,
200 Packet::Disconnect => packet_type::DISCONNECT,
201 }
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208
209 #[test]
210 fn test_ack_reason() {
211 assert_eq!(ConnectAckReason::ConnectionAccepted.reason(), "Connection Accepted");
212 assert_eq!(
213 ConnectAckReason::UnacceptableProtocolVersion.reason(),
214 "Connection Refused, unacceptable protocol version"
215 );
216 assert_eq!(
217 ConnectAckReason::IdentifierRejected.reason(),
218 "Connection Refused, identifier rejected"
219 );
220 assert_eq!(
221 ConnectAckReason::ServiceUnavailable.reason(),
222 "Connection Refused, Server unavailable"
223 );
224 assert_eq!(
225 ConnectAckReason::BadUserNameOrPassword.reason(),
226 "Connection Refused, bad user name or password"
227 );
228 assert_eq!(
229 ConnectAckReason::NotAuthorized.reason(),
230 "Connection Refused, not authorized"
231 );
232 }
233}