rumq_core/mqtt4/
packets.rs

1use crate::mqtt4::QoS;
2use std::fmt;
3
4/// Packet identifier for packets types that require broker to acknowledge
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
6pub struct PacketIdentifier(pub u16);
7
8impl From<u16> for PacketIdentifier {
9    fn from(value: u16) -> Self {
10        PacketIdentifier(value)
11    }
12}
13
14/// Mqtt protocol version
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum Protocol {
17    MQTT(u8),
18}
19
20/// Mqtt connect packet representation
21#[derive(Clone, PartialEq)]
22pub struct Connect {
23    /// Mqtt protocol version
24    pub protocol: Protocol,
25    /// Mqtt keep alive time
26    pub keep_alive: u16,
27    /// Client Id
28    pub client_id: String,
29    /// Clean session. Asks the broker to clear previous state
30    pub clean_session: bool,
31    /// Will that broker needs to publish when the client disconnects
32    pub last_will: Option<LastWill>,
33    /// Username of the client
34    pub username: Option<String>,
35    /// Password of the client
36    pub password: Option<String>,
37}
38
39impl Connect {
40    /// Creates a new mqtt connect packet
41    pub fn new<S: Into<String>>(id: S) -> Connect {
42        Connect {
43            protocol: Protocol::MQTT(4),
44            keep_alive: 10,
45            client_id: id.into(),
46            clean_session: true,
47            last_will: None,
48            username: None,
49            password: None,
50        }
51    }
52
53    /// Sets username
54    pub fn set_username<S: Into<String>>(&mut self, u: S) -> &mut Connect {
55        self.username = Some(u.into());
56        self
57    }
58
59    /// Sets password
60    pub fn set_password<S: Into<String>>(&mut self, p: S) -> &mut Connect {
61        self.password = Some(p.into());
62        self
63    }
64
65    pub(crate) fn len(&self) -> usize {
66        let mut len = 8 + "MQTT".len() + self.client_id.len();
67
68        // lastwill len
69        if let Some(ref last_will) = self.last_will {
70            len += 4 + last_will.topic.len() + last_will.message.len();
71        }
72
73        // username len
74        if let Some(ref username) = self.username {
75            len += 2 + username.len();
76        }
77
78        // passwork len
79        if let Some(ref password) = self.password {
80            len += 2 + password.len();
81        }
82
83        len
84    }
85}
86
87/// Connection return code sent by the server
88#[derive(Debug, Clone, Copy, PartialEq)]
89#[repr(u8)]
90pub enum ConnectReturnCode {
91    Accepted = 0,
92    RefusedProtocolVersion,
93    RefusedIdentifierRejected,
94    ServerUnavailable,
95    BadUsernamePassword,
96    NotAuthorized,
97}
98
99/// Connack packet
100#[derive(Debug, Clone, Copy, PartialEq)]
101pub struct Connack {
102    pub session_present: bool,
103    pub code: ConnectReturnCode,
104}
105
106impl Connack {
107    /// Creates a new connack packet
108    pub fn new(code: ConnectReturnCode, session_present: bool) -> Connack {
109        Connack { code, session_present }
110    }
111}
112
113/// Last will of the connection
114#[derive(Debug, Clone, PartialEq)]
115pub struct LastWill {
116    pub topic: String,
117    pub message: String,
118    pub qos: QoS,
119    pub retain: bool,
120}
121
122/// Publish packet
123#[derive(Clone, PartialEq)]
124pub struct Publish {
125    pub dup: bool,
126    pub qos: QoS,
127    pub retain: bool,
128    pub topic_name: String,
129    pub pkid: Option<PacketIdentifier>,
130    pub payload: Vec<u8>,
131}
132
133impl Publish {
134    /// Creates a new publish packet
135    //TODO: maybe this should become private, or just removed and inserted into Publish::new()
136    pub fn new<S: Into<String>, P: Into<Vec<u8>>>(topic: S, qos: QoS, payload: P) -> Publish {
137        Publish {
138            dup: false,
139            qos,
140            retain: false,
141            pkid: None,
142            topic_name: topic.into(),
143            payload: payload.into(),
144        }
145    }
146
147    /// Sets packet identifier
148    pub fn set_pkid<P: Into<PacketIdentifier>>(&mut self, pkid: P) -> &mut Self {
149        self.pkid = Some(pkid.into());
150        self
151    }
152    pub fn set_retain(&mut self, retain: bool) -> &mut Self {
153        self.retain = retain;
154        self
155    }
156}
157
158/// Subscriber packet
159#[derive(Clone, PartialEq)]
160pub struct Subscribe {
161    pub pkid: PacketIdentifier,
162    pub topics: Vec<SubscribeTopic>,
163}
164
165impl Subscribe {
166    //TODO: maybe this should become private, or just removed and inserted into Subscribe::new()
167    /// Creates a new subscription packet
168    pub fn new<S: Into<String>>(topic: S, qos: QoS) -> Subscribe {
169        let topic = SubscribeTopic {
170            topic_path: topic.into(),
171            qos,
172        };
173
174        Subscribe {
175            pkid: PacketIdentifier(0),
176            topics: vec![topic],
177        }
178    }
179
180    /// Creates an empty subscription packet
181    pub fn empty_subscribe() -> Subscribe {
182        Subscribe {
183            pkid: PacketIdentifier(0),
184            topics: Vec::new(),
185        }
186    }
187
188    pub fn add(&mut self, topic: String, qos: QoS) -> &mut Self {
189        let topic = SubscribeTopic { topic_path: topic, qos };
190        self.topics.push(topic);
191        self
192    }
193}
194
195/// Subscription topic
196#[derive(Clone, PartialEq)]
197pub struct SubscribeTopic {
198    pub topic_path: String,
199    pub qos: QoS,
200}
201
202/// Subscription return code sent by the broker
203#[derive(Debug, Clone, Copy, PartialEq, Eq)]
204pub enum SubscribeReturnCodes {
205    Success(QoS),
206    Failure,
207}
208
209/// Subscription acknowledgement
210#[derive(Debug, Clone, PartialEq)]
211pub struct Suback {
212    pub pkid: PacketIdentifier,
213    pub return_codes: Vec<SubscribeReturnCodes>,
214}
215
216impl Suback {
217    /// Creates a new subscription acknowledgement packet
218    pub fn new(pkid: PacketIdentifier, return_codes: Vec<SubscribeReturnCodes>) -> Suback {
219        Suback { pkid, return_codes }
220    }
221}
222
223/// Unsubscribe packet
224#[derive(Debug, Clone, PartialEq)]
225pub struct Unsubscribe {
226    pub pkid: PacketIdentifier,
227    pub topics: Vec<String>,
228}
229
230impl fmt::Debug for Publish {
231    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232        write!(
233            f,
234            "Topic = {}, Qos = {:?}, Retain = {}, Pkid = {:?}, Payload Size = {}",
235            self.topic_name,
236            self.qos,
237            self.retain,
238            self.pkid,
239            self.payload.len()
240        )
241    }
242}
243
244impl fmt::Debug for Connect {
245    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246        write!(
247            f,
248            "Protocol = {:?}, Keep alive = {:?}, Client id = {}, Clean session = {}",
249            self.protocol, self.keep_alive, self.client_id, self.clean_session,
250        )
251    }
252}
253
254impl fmt::Debug for Subscribe {
255    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256        write!(f, "Filters = {:?}, Packet id = {:?}", self.pkid, self.topics)
257    }
258}
259
260impl fmt::Debug for SubscribeTopic {
261    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262        write!(f, "Filter = {}, Qos = {:?}", self.topic_path, self.qos)
263    }
264}