minimq/
lib.rs

1#![cfg_attr(not(test), no_std)]
2//! # MiniMQ
3//! Provides a minimal MQTTv5 client and message parsing for the MQTT version 5 protocol.
4//!
5//! This crate provides a minimalistic MQTT 5 client that can be used to publish topics to an MQTT
6//! broker and subscribe to receive messages on specific topics.
7//!
8//! # Limitations
9//! This library does not currently support the following elements:
10//! * Subscribing above Quality-of-service `AtMostOnce`
11//! * Server Authentication
12//! * Topic aliases
13//!
14//! # Requirements
15//! This library requires that the user provide it an object that implements a basic TcpStack that
16//! can be used as the transport layer for MQTT communications.
17//!
18//! The maximum message size is configured through generic parameters. This allows the maximum
19//! message size to be configured by the user. Note that buffers will be allocated on the stack, so it
20//! is important to select a size such that the stack does not overflow.
21//!
22//! # Example
23//! Below is a sample snippet showing how this library is used.
24//!
25//! ```no_run
26//! use minimq::{ConfigBuilder, Minimq, Publication};
27//!
28//! // Construct an MQTT client with a maximum packet size of 256 bytes
29//! // and a maximum of 16 messages that are allowed to be "in flight".
30//! // Messages are "in flight" if QoS::AtLeastOnce has not yet been acknowledged (PUBACK)
31//! // or QoS::ExactlyOnce has not been completed (PUBCOMP).
32//! // Connect to a broker at localhost - Use a client ID of "test".
33//! let mut buffer = [0; 256];
34//! let localhost: std::net::IpAddr = "127.0.0.1".parse().unwrap();
35//! let mut mqtt: Minimq<'_, _, _, minimq::broker::IpBroker> = Minimq::new(
36//!         std_embedded_nal::Stack::default(),
37//!         std_embedded_time::StandardClock::default(),
38//!         ConfigBuilder::new(localhost.into(), &mut buffer)
39//!             .client_id("test").unwrap(),
40//!         );
41//!
42//! let mut subscribed = false;
43//!
44//! loop {
45//!     if mqtt.client().is_connected() && !subscribed {
46//!         mqtt.client().subscribe(&["topic".into()], &[]).unwrap();
47//!         subscribed = true;
48//!     }
49//!
50//!     // The client must be continually polled to update the MQTT state machine.
51//!     mqtt.poll(|client, topic, message, properties| {
52//!         match topic {
53//!             "topic" => {
54//!                println!("{:?}", message);
55//!                client.publish(Publication::new("echo", message)).unwrap();
56//!             },
57//!             topic => println!("Unknown topic: {}", topic),
58//!         };
59//!     }).unwrap();
60//! }
61//! ```
62
63pub mod broker;
64pub mod config;
65mod de;
66mod message_types;
67pub mod mqtt_client;
68mod network_manager;
69mod packets;
70mod properties;
71pub mod publication;
72mod reason_codes;
73mod republication;
74mod ring_buffer;
75mod ser;
76mod session_state;
77pub mod types;
78mod varint;
79mod will;
80
81pub use broker::Broker;
82pub use config::ConfigBuilder;
83pub use properties::Property;
84pub use publication::Publication;
85pub use reason_codes::ReasonCode;
86pub use will::Will;
87
88pub use embedded_nal;
89pub use embedded_time;
90pub use mqtt_client::Minimq;
91use num_enum::TryFromPrimitive;
92
93pub use de::Error as DeError;
94pub use ser::Error as SerError;
95
96#[cfg(feature = "logging")]
97pub(crate) use log::{debug, error, info, trace, warn};
98
99/// Default port number for unencrypted MQTT traffic
100///
101/// # Note:
102/// See [IANA Port Numbers](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt)
103pub const MQTT_INSECURE_DEFAULT_PORT: u16 = 1883;
104
105/// Default port number for encrypted MQTT traffic
106///
107/// # Note:
108/// See [IANA Port Numbers](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt)
109pub const MQTT_SECURE_DEFAULT_PORT: u16 = 8883;
110
111/// The quality-of-service for an MQTT message.
112#[derive(Debug, Copy, Clone, PartialEq, TryFromPrimitive, PartialOrd)]
113#[repr(u8)]
114pub enum QoS {
115    /// A packet will be delivered at most once, but may not be delivered at all.
116    AtMostOnce = 0,
117
118    /// A packet will be delivered at least one time, but possibly more than once.
119    AtLeastOnce = 1,
120
121    /// A packet will be delivered exactly one time.
122    ExactlyOnce = 2,
123}
124
125/// The retained status for an MQTT message.
126#[derive(Debug, Copy, Clone, PartialEq, TryFromPrimitive)]
127#[repr(u8)]
128pub enum Retain {
129    /// The message shall not be retained by the broker.
130    NotRetained = 0,
131
132    /// The message shall be marked for retention by the broker.
133    Retained = 1,
134}
135
136/// Errors that are specific to the MQTT protocol implementation.
137#[non_exhaustive]
138#[derive(Debug, Copy, Clone, PartialEq)]
139pub enum ProtocolError {
140    ProvidedClientIdTooLong,
141    UnexpectedPacket,
142    InvalidProperty,
143    MalformedPacket,
144    BufferSize,
145    BadIdentifier,
146    Unacknowledged,
147    WrongQos,
148    UnsupportedPacket,
149    NoTopic,
150    AuthAlreadySpecified,
151    WillAlreadySpecified,
152    Failed(ReasonCode),
153    Serialization(SerError),
154    Deserialization(DeError),
155}
156
157#[derive(Debug, PartialEq)]
158pub enum PubError<T, E> {
159    Error(Error<T>),
160    Serialization(E),
161}
162
163impl<T, E> From<crate::ser::PubError<E>> for PubError<T, E> {
164    fn from(e: crate::ser::PubError<E>) -> Self {
165        match e {
166            crate::ser::PubError::Other(e) => crate::PubError::Serialization(e),
167            crate::ser::PubError::Error(e) => crate::PubError::Error(crate::Error::Minimq(
168                crate::MinimqError::Protocol(ProtocolError::from(e)),
169            )),
170        }
171    }
172}
173
174impl<T, E> From<Error<T>> for PubError<T, E> {
175    fn from(e: Error<T>) -> Self {
176        Self::Error(e)
177    }
178}
179
180impl From<crate::ser::Error> for ProtocolError {
181    fn from(err: crate::ser::Error) -> Self {
182        ProtocolError::Serialization(err)
183    }
184}
185
186impl From<crate::de::Error> for ProtocolError {
187    fn from(err: crate::de::Error) -> Self {
188        ProtocolError::Deserialization(err)
189    }
190}
191
192impl From<ReasonCode> for ProtocolError {
193    fn from(code: ReasonCode) -> Self {
194        ProtocolError::Failed(code)
195    }
196}
197
198#[derive(Debug, PartialEq)]
199#[non_exhaustive]
200pub enum MinimqError {
201    Protocol(ProtocolError),
202    Clock(embedded_time::clock::Error),
203}
204
205/// Possible errors encountered during an MQTT connection.
206#[derive(Debug, PartialEq)]
207#[non_exhaustive]
208pub enum Error<E> {
209    WriteFail,
210    NotReady,
211    Unsupported,
212    NoResponseTopic,
213    SessionReset,
214    Network(E),
215    Minimq(MinimqError),
216}
217
218impl<E> From<MinimqError> for Error<E> {
219    fn from(minimq: MinimqError) -> Self {
220        Error::Minimq(minimq)
221    }
222}
223
224impl From<embedded_time::clock::Error> for MinimqError {
225    fn from(clock: embedded_time::clock::Error) -> Self {
226        MinimqError::Clock(clock)
227    }
228}
229
230impl<E> From<ProtocolError> for Error<E> {
231    fn from(p: ProtocolError) -> Self {
232        Error::Minimq(p.into())
233    }
234}
235
236impl<E> From<embedded_time::clock::Error> for Error<E> {
237    fn from(clock: embedded_time::clock::Error) -> Self {
238        Error::Minimq(clock.into())
239    }
240}
241
242impl From<ProtocolError> for MinimqError {
243    fn from(error: ProtocolError) -> Self {
244        MinimqError::Protocol(error)
245    }
246}
247
248#[doc(hidden)]
249#[cfg(not(feature = "logging"))]
250mod mqtt_log {
251    #[doc(hidden)]
252    #[macro_export]
253    macro_rules! trace {
254        ($($arg:tt)+) => {
255            ()
256        };
257    }
258
259    #[doc(hidden)]
260    #[macro_export]
261    macro_rules! debug {
262        ($($arg:tt)+) => {
263            ()
264        };
265    }
266
267    #[doc(hidden)]
268    #[macro_export]
269    macro_rules! info {
270        ($($arg:tt)+) => {
271            ()
272        };
273    }
274
275    #[doc(hidden)]
276    #[macro_export]
277    macro_rules! warn {
278        ($($arg:tt)+) => {
279            ()
280        };
281    }
282
283    #[doc(hidden)]
284    #[macro_export]
285    macro_rules! error {
286        ($($arg:tt)+) => {
287            ()
288        };
289    }
290}