Skip to main content

mqtt5_protocol/types/
message.rs

1use super::{PublishProperties, QoS};
2use crate::prelude::{String, Vec};
3
4#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
5pub struct WillMessage {
6    pub topic: String,
7    pub payload: Vec<u8>,
8    pub qos: QoS,
9    pub retain: bool,
10    pub properties: WillProperties,
11}
12
13impl WillMessage {
14    #[must_use]
15    pub fn new(topic: impl Into<String>, payload: impl Into<Vec<u8>>) -> Self {
16        Self {
17            topic: topic.into(),
18            payload: payload.into(),
19            qos: QoS::AtMostOnce,
20            retain: false,
21            properties: WillProperties::default(),
22        }
23    }
24
25    #[must_use]
26    pub fn with_qos(mut self, qos: QoS) -> Self {
27        self.qos = qos;
28        self
29    }
30
31    #[must_use]
32    pub fn with_retain(mut self, retain: bool) -> Self {
33        self.retain = retain;
34        self
35    }
36}
37
38#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
39pub struct WillProperties {
40    pub will_delay_interval: Option<u32>,
41    pub payload_format_indicator: Option<bool>,
42    pub message_expiry_interval: Option<u32>,
43    pub content_type: Option<String>,
44    pub response_topic: Option<String>,
45    pub correlation_data: Option<Vec<u8>>,
46    pub user_properties: Vec<(String, String)>,
47}
48
49impl WillProperties {
50    pub fn apply_to_publish_properties(
51        &self,
52        props: &mut crate::protocol::v5::properties::Properties,
53    ) {
54        if let Some(format) = self.payload_format_indicator {
55            props.set_payload_format_indicator(format);
56        }
57        if let Some(expiry) = self.message_expiry_interval {
58            props.set_message_expiry_interval(expiry);
59        }
60        if let Some(ref content_type) = self.content_type {
61            props.set_content_type(content_type.clone());
62        }
63        if let Some(ref response_topic) = self.response_topic {
64            props.set_response_topic(response_topic.clone());
65        }
66        if let Some(ref correlation_data) = self.correlation_data {
67            props.set_correlation_data(correlation_data.clone().into());
68        }
69        for (key, value) in &self.user_properties {
70            props.add_user_property(key.clone(), value.clone());
71        }
72    }
73}
74
75impl From<WillProperties> for crate::protocol::v5::properties::Properties {
76    fn from(will_props: WillProperties) -> Self {
77        let mut properties = crate::protocol::v5::properties::Properties::default();
78
79        if let Some(delay) = will_props.will_delay_interval {
80            if properties
81                .add(
82                    crate::protocol::v5::properties::PropertyId::WillDelayInterval,
83                    crate::protocol::v5::properties::PropertyValue::FourByteInteger(delay),
84                )
85                .is_err()
86            {
87                crate::prelude::warn_log!("Failed to add will delay interval property");
88            }
89        }
90
91        if let Some(format) = will_props.payload_format_indicator {
92            if properties
93                .add(
94                    crate::protocol::v5::properties::PropertyId::PayloadFormatIndicator,
95                    crate::protocol::v5::properties::PropertyValue::Byte(u8::from(format)),
96                )
97                .is_err()
98            {
99                crate::prelude::warn_log!("Failed to add payload format indicator property");
100            }
101        }
102
103        if let Some(expiry) = will_props.message_expiry_interval {
104            if properties
105                .add(
106                    crate::protocol::v5::properties::PropertyId::MessageExpiryInterval,
107                    crate::protocol::v5::properties::PropertyValue::FourByteInteger(expiry),
108                )
109                .is_err()
110            {
111                crate::prelude::warn_log!("Failed to add message expiry interval property");
112            }
113        }
114
115        if let Some(content_type) = will_props.content_type {
116            if properties
117                .add(
118                    crate::protocol::v5::properties::PropertyId::ContentType,
119                    crate::protocol::v5::properties::PropertyValue::Utf8String(content_type),
120                )
121                .is_err()
122            {
123                crate::prelude::warn_log!("Failed to add content type property");
124            }
125        }
126
127        if let Some(response_topic) = will_props.response_topic {
128            if properties
129                .add(
130                    crate::protocol::v5::properties::PropertyId::ResponseTopic,
131                    crate::protocol::v5::properties::PropertyValue::Utf8String(response_topic),
132                )
133                .is_err()
134            {
135                crate::prelude::warn_log!("Failed to add response topic property");
136            }
137        }
138
139        if let Some(correlation_data) = will_props.correlation_data {
140            if properties
141                .add(
142                    crate::protocol::v5::properties::PropertyId::CorrelationData,
143                    crate::protocol::v5::properties::PropertyValue::BinaryData(
144                        correlation_data.into(),
145                    ),
146                )
147                .is_err()
148            {
149                crate::prelude::warn_log!("Failed to add correlation data property");
150            }
151        }
152
153        for (key, value) in will_props.user_properties {
154            if properties
155                .add(
156                    crate::protocol::v5::properties::PropertyId::UserProperty,
157                    crate::protocol::v5::properties::PropertyValue::Utf8StringPair(key, value),
158                )
159                .is_err()
160            {
161                crate::prelude::warn_log!("Failed to add user property");
162            }
163        }
164
165        properties
166    }
167}
168
169#[derive(Debug, Clone)]
170pub struct Message {
171    pub topic: String,
172    pub payload: Vec<u8>,
173    pub qos: QoS,
174    pub retain: bool,
175    pub properties: MessageProperties,
176}
177
178impl From<crate::packet::publish::PublishPacket> for Message {
179    fn from(packet: crate::packet::publish::PublishPacket) -> Self {
180        Self {
181            topic: packet.topic_name,
182            payload: packet.payload.to_vec(),
183            qos: packet.qos,
184            retain: packet.retain,
185            properties: MessageProperties::from(packet.properties),
186        }
187    }
188}
189
190#[derive(Debug, Clone, Default)]
191pub struct MessageProperties {
192    pub payload_format_indicator: Option<bool>,
193    pub message_expiry_interval: Option<u32>,
194    pub response_topic: Option<String>,
195    pub correlation_data: Option<Vec<u8>>,
196    pub user_properties: Vec<(String, String)>,
197    pub subscription_identifiers: Vec<u32>,
198    pub content_type: Option<String>,
199}
200
201impl From<crate::protocol::v5::properties::Properties> for MessageProperties {
202    fn from(props: crate::protocol::v5::properties::Properties) -> Self {
203        use crate::protocol::v5::properties::{PropertyId, PropertyValue};
204
205        let mut result = Self::default();
206
207        for (id, value) in props.iter() {
208            match (id, value) {
209                (PropertyId::PayloadFormatIndicator, PropertyValue::Byte(v)) => {
210                    result.payload_format_indicator = Some(v != &0);
211                }
212                (PropertyId::MessageExpiryInterval, PropertyValue::FourByteInteger(v)) => {
213                    result.message_expiry_interval = Some(*v);
214                }
215                (PropertyId::ResponseTopic, PropertyValue::Utf8String(v)) => {
216                    result.response_topic = Some(v.clone());
217                }
218                (PropertyId::CorrelationData, PropertyValue::BinaryData(v)) => {
219                    result.correlation_data = Some(v.to_vec());
220                }
221                (PropertyId::UserProperty, PropertyValue::Utf8StringPair(k, v)) => {
222                    result.user_properties.push((k.clone(), v.clone()));
223                }
224                (PropertyId::SubscriptionIdentifier, PropertyValue::VariableByteInteger(v)) => {
225                    result.subscription_identifiers.push(*v);
226                }
227                (PropertyId::ContentType, PropertyValue::Utf8String(v)) => {
228                    result.content_type = Some(v.clone());
229                }
230                _ => {}
231            }
232        }
233
234        result
235    }
236}
237
238impl From<MessageProperties> for PublishProperties {
239    fn from(msg_props: MessageProperties) -> Self {
240        Self {
241            payload_format_indicator: msg_props.payload_format_indicator,
242            message_expiry_interval: msg_props.message_expiry_interval,
243            topic_alias: None,
244            response_topic: msg_props.response_topic,
245            correlation_data: msg_props.correlation_data,
246            user_properties: msg_props.user_properties,
247            subscription_identifiers: msg_props.subscription_identifiers,
248            content_type: msg_props.content_type,
249        }
250    }
251}