mqrstt/
connect_options.rs

1use std::time::Duration;
2
3use crate::util::constants::DEFAULT_RECEIVE_MAXIMUM;
4use crate::{
5    packets::{ConnectProperties, LastWill},
6    util::constants::MAXIMUM_PACKET_SIZE,
7};
8
9#[derive(Debug, thiserror::Error)]
10pub enum ConnectOptionsError {
11    #[error("Maximum packet size is exceeded. Maximum is {MAXIMUM_PACKET_SIZE}, user provided: {0}")]
12    MaximumPacketSizeExceeded(u32),
13}
14
15/// Options for the connection to the MQTT broker
16#[derive(Debug, Clone)]
17pub struct ConnectOptions {
18    /// client identifier
19    client_id: Box<str>,
20    /// keep alive time to send pingreq to broker when the connection is idle
21    pub(crate) keep_alive_interval: Duration,
22    /// clean or persistent session indicator
23    pub(crate) clean_start: bool,
24    /// username and password
25    username: Option<Box<str>>,
26    password: Option<Box<str>>,
27
28    // MQTT v5 Connect Properties:
29    session_expiry_interval: Option<u32>,
30
31    /// The maximum number of packets that will be inflight from the broker to this client.
32    receive_maximum: Option<u16>,
33
34    /// The maximum number of packets that can be inflight from this client to the broker.
35    send_maximum: Option<u16>,
36
37    maximum_packet_size: Option<u32>,
38    topic_alias_maximum: Option<u16>,
39    request_response_information: Option<u8>,
40    request_problem_information: Option<u8>,
41    user_properties: Vec<(Box<str>, Box<str>)>,
42    authentication_method: Option<Box<str>>,
43    authentication_data: Option<Vec<u8>>,
44
45    /// Last will that will be issued on unexpected disconnect
46    last_will: Option<LastWill>,
47}
48
49impl Default for ConnectOptions {
50    fn default() -> Self {
51        Self {
52            keep_alive_interval: Duration::from_secs(60),
53            clean_start: true,
54            client_id: Box::from("ChangeClientId_MQRSTT"),
55            username: None,
56            password: None,
57            session_expiry_interval: None,
58            receive_maximum: None,
59            send_maximum: None,
60            maximum_packet_size: None,
61            topic_alias_maximum: None,
62            request_response_information: None,
63            request_problem_information: None,
64            user_properties: Vec::new(),
65            authentication_method: None,
66            authentication_data: None,
67            last_will: None,
68        }
69    }
70}
71
72impl ConnectOptions {
73    /// Create a new [`ConnectOptions`]
74    ///
75    /// Be aware:
76    /// This client does not restrict the client identifier in any way. However, the MQTT v5.0 specification does.
77    /// It is thus recommended to use a client id that is compatible with the MQTT v5.0 specification.
78    ///     - 1 to 23 bytes UTF-8 bytes.
79    ///     - Contains [a-zA-Z0-9] characters only.
80    ///
81    /// Some brokers accept longer client ids with different characters
82    pub fn new<S: AsRef<str>>(client_id: S) -> Self {
83        Self {
84            keep_alive_interval: Duration::from_secs(60),
85            clean_start: true,
86            client_id: client_id.as_ref().into(),
87            username: None,
88            password: None,
89
90            session_expiry_interval: None,
91            receive_maximum: None,
92            send_maximum: None,
93            maximum_packet_size: None,
94            topic_alias_maximum: None,
95            request_response_information: None,
96            request_problem_information: None,
97            user_properties: vec![],
98            authentication_method: None,
99            authentication_data: None,
100            last_will: None,
101        }
102    }
103
104    pub(crate) fn create_connect_from_options(&self) -> crate::packets::Packet {
105        let connect_properties = ConnectProperties {
106            session_expiry_interval: self.session_expiry_interval,
107            receive_maximum: self.receive_maximum,
108            maximum_packet_size: self.maximum_packet_size,
109            topic_alias_maximum: self.topic_alias_maximum,
110            request_response_information: self.request_response_information,
111            request_problem_information: self.request_problem_information,
112            user_properties: self.user_properties.clone(),
113            authentication_method: self.authentication_method.clone(),
114            authentication_data: self.authentication_data.clone(),
115        };
116
117        let connect = crate::packets::Connect {
118            client_id: self.client_id.clone(),
119            clean_start: self.clean_start,
120            keep_alive: self.keep_alive_interval.as_secs() as u16,
121            username: self.username.clone(),
122            password: self.password.clone(),
123            connect_properties,
124            protocol_version: crate::packets::ProtocolVersion::V5,
125            last_will: self.last_will.clone(),
126        };
127
128        crate::packets::Packet::Connect(connect)
129    }
130
131    /// The Client Identifier (ClientID) identifies the Client to the Server. Each Client connecting to the Server has a unique ClientID.
132    /// The ClientID MUST be used by Clients and by Servers to identify state that they hold relating to this MQTT Session between the Client and the Server [MQTT-3.1.3-2].
133    /// More info here: <https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059>
134    ///
135    /// Non unique client ids often result in connect, disconnect loops due to auto reconnects and forced disconnects
136    pub fn get_client_id(&self) -> &str {
137        &self.client_id
138    }
139    /// The Client Identifier (ClientID) identifies the Client to the Server. Each Client connecting to the Server has a unique ClientID.
140    /// The ClientID MUST be used by Clients and by Servers to identify state that they hold relating to this MQTT Session between the Client and the Server [MQTT-3.1.3-2].
141    /// More info here: <https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059>
142    ///
143    /// Non unique client ids often result in connect, disconnect loops due to auto reconnects and forced disconnects
144    pub fn set_client_id<S: AsRef<str>>(&mut self, client_id: S) -> &mut Self {
145        self.client_id = client_id.as_ref().into();
146        self
147    }
148
149    /// This specifies whether the Connection starts a new Session or is a continuation of an existing Session.
150    /// More info here: <https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901039>
151    pub fn get_clean_start(&self) -> bool {
152        self.clean_start
153    }
154    /// This specifies whether the Connection starts a new Session or is a continuation of an existing Session.
155    /// More info here: <https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901039>
156    pub fn set_clean_start(&mut self, clean_start: bool) -> &mut Self {
157        self.clean_start = clean_start;
158        self
159    }
160
161    pub fn get_username(&self) -> Option<&str> {
162        self.username.as_ref().map(Box::<str>::as_ref)
163    }
164    pub fn set_username<S: AsRef<str>>(&mut self, username: S) -> &mut Self {
165        self.username = Some(username.as_ref().into());
166        self
167    }
168    pub fn get_password(&self) -> Option<&str> {
169        self.password.as_ref().map(Box::<str>::as_ref)
170    }
171    pub fn set_password<S: AsRef<str>>(&mut self, password: S) -> &mut Self {
172        self.password = Some(password.as_ref().into());
173        self
174    }
175
176    /// Get the Session Expiry Interval in seconds.
177    /// If the Session Expiry Interval is absent the value 0 is used. If it is set to 0, or is absent, the Session ends when the Network Connection is closed.
178    /// If the Session Expiry Interval is 0xFFFFFFFF (UINT_MAX), the Session does not expire.
179    /// More info here: <https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901211>
180    pub fn get_session_expiry_interval(&self) -> Option<u32> {
181        self.session_expiry_interval
182    }
183    /// Set the Session Expiry Interval in seconds.
184    /// If the Session Expiry Interval is absent the value 0 is used. If it is set to 0, or is absent, the Session ends when the Network Connection is closed.
185    /// If the Session Expiry Interval is 0xFFFFFFFF (UINT_MAX), the Session does not expire.
186    /// More info here: <https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901211>
187    pub fn set_session_expiry_interval(&mut self, session_expiry_interval: u32) -> &mut Self {
188        self.session_expiry_interval = Some(session_expiry_interval);
189        self
190    }
191
192    /// Get the current keep alive interval for the MQTT protocol
193    /// This time is used in Ping Pong when natural traffic is absent
194    /// The granularity is in seconds!
195    pub fn get_keep_alive_interval(&self) -> Duration {
196        self.keep_alive_interval
197    }
198    /// Set the keep alive interval for the MQTT protocol
199    /// This time is used in Ping Pong when natural traffic is absent
200    /// The granularity is in seconds!
201    pub fn set_keep_alive_interval(&mut self, keep_alive_interval: Duration) -> &mut Self {
202        self.keep_alive_interval = Duration::from_secs(keep_alive_interval.as_secs());
203        self
204    }
205
206    pub fn set_last_will(&mut self, last_will: LastWill) -> &mut Self {
207        self.last_will = Some(last_will);
208        self
209    }
210    pub fn get_last_will(&self) -> Option<&LastWill> {
211        self.last_will.as_ref()
212    }
213
214    pub fn set_receive_maximum(&mut self, receive_maximum: u16) -> &mut Self {
215        self.receive_maximum = Some(receive_maximum);
216        self
217    }
218    pub fn receive_maximum(&self) -> u16 {
219        self.receive_maximum.unwrap_or(DEFAULT_RECEIVE_MAXIMUM)
220    }
221
222    pub fn set_maximum_packet_size(&mut self, maximum_packet_size: u32) -> Result<&mut Self, ConnectOptionsError> {
223        if maximum_packet_size > MAXIMUM_PACKET_SIZE {
224            Err(ConnectOptionsError::MaximumPacketSizeExceeded(maximum_packet_size))
225        } else {
226            self.maximum_packet_size = Some(maximum_packet_size);
227            Ok(self)
228        }
229    }
230    pub fn maximum_packet_size(&self) -> usize {
231        self.maximum_packet_size.unwrap_or(MAXIMUM_PACKET_SIZE) as usize
232    }
233
234    pub fn set_send_maximum(&mut self, send_maximum: u16) -> &mut Self {
235        self.send_maximum = Some(send_maximum);
236        self
237    }
238    pub fn send_maximum(&self) -> u16 {
239        self.send_maximum.unwrap_or(DEFAULT_RECEIVE_MAXIMUM)
240    }
241}