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 From<WillProperties> for crate::protocol::v5::properties::Properties {
50    fn from(will_props: WillProperties) -> Self {
51        let mut properties = crate::protocol::v5::properties::Properties::default();
52
53        if let Some(delay) = will_props.will_delay_interval {
54            if properties
55                .add(
56                    crate::protocol::v5::properties::PropertyId::WillDelayInterval,
57                    crate::protocol::v5::properties::PropertyValue::FourByteInteger(delay),
58                )
59                .is_err()
60            {
61                crate::prelude::warn_log!("Failed to add will delay interval property");
62            }
63        }
64
65        if let Some(format) = will_props.payload_format_indicator {
66            if properties
67                .add(
68                    crate::protocol::v5::properties::PropertyId::PayloadFormatIndicator,
69                    crate::protocol::v5::properties::PropertyValue::Byte(u8::from(format)),
70                )
71                .is_err()
72            {
73                crate::prelude::warn_log!("Failed to add payload format indicator property");
74            }
75        }
76
77        if let Some(expiry) = will_props.message_expiry_interval {
78            if properties
79                .add(
80                    crate::protocol::v5::properties::PropertyId::MessageExpiryInterval,
81                    crate::protocol::v5::properties::PropertyValue::FourByteInteger(expiry),
82                )
83                .is_err()
84            {
85                crate::prelude::warn_log!("Failed to add message expiry interval property");
86            }
87        }
88
89        if let Some(content_type) = will_props.content_type {
90            if properties
91                .add(
92                    crate::protocol::v5::properties::PropertyId::ContentType,
93                    crate::protocol::v5::properties::PropertyValue::Utf8String(content_type),
94                )
95                .is_err()
96            {
97                crate::prelude::warn_log!("Failed to add content type property");
98            }
99        }
100
101        if let Some(response_topic) = will_props.response_topic {
102            if properties
103                .add(
104                    crate::protocol::v5::properties::PropertyId::ResponseTopic,
105                    crate::protocol::v5::properties::PropertyValue::Utf8String(response_topic),
106                )
107                .is_err()
108            {
109                crate::prelude::warn_log!("Failed to add response topic property");
110            }
111        }
112
113        if let Some(correlation_data) = will_props.correlation_data {
114            if properties
115                .add(
116                    crate::protocol::v5::properties::PropertyId::CorrelationData,
117                    crate::protocol::v5::properties::PropertyValue::BinaryData(
118                        correlation_data.into(),
119                    ),
120                )
121                .is_err()
122            {
123                crate::prelude::warn_log!("Failed to add correlation data property");
124            }
125        }
126
127        for (key, value) in will_props.user_properties {
128            if properties
129                .add(
130                    crate::protocol::v5::properties::PropertyId::UserProperty,
131                    crate::protocol::v5::properties::PropertyValue::Utf8StringPair(key, value),
132                )
133                .is_err()
134            {
135                crate::prelude::warn_log!("Failed to add user property");
136            }
137        }
138
139        properties
140    }
141}
142
143#[derive(Debug, Clone)]
144pub struct Message {
145    pub topic: String,
146    pub payload: Vec<u8>,
147    pub qos: QoS,
148    pub retain: bool,
149    pub properties: MessageProperties,
150}
151
152impl From<crate::packet::publish::PublishPacket> for Message {
153    fn from(packet: crate::packet::publish::PublishPacket) -> Self {
154        Self {
155            topic: packet.topic_name,
156            payload: packet.payload.to_vec(),
157            qos: packet.qos,
158            retain: packet.retain,
159            properties: MessageProperties::from(packet.properties),
160        }
161    }
162}
163
164#[derive(Debug, Clone, Default)]
165pub struct MessageProperties {
166    pub payload_format_indicator: Option<bool>,
167    pub message_expiry_interval: Option<u32>,
168    pub response_topic: Option<String>,
169    pub correlation_data: Option<Vec<u8>>,
170    pub user_properties: Vec<(String, String)>,
171    pub subscription_identifiers: Vec<u32>,
172    pub content_type: Option<String>,
173}
174
175impl From<crate::protocol::v5::properties::Properties> for MessageProperties {
176    fn from(props: crate::protocol::v5::properties::Properties) -> Self {
177        use crate::protocol::v5::properties::{PropertyId, PropertyValue};
178
179        let mut result = Self::default();
180
181        for (id, value) in props.iter() {
182            match (id, value) {
183                (PropertyId::PayloadFormatIndicator, PropertyValue::Byte(v)) => {
184                    result.payload_format_indicator = Some(v != &0);
185                }
186                (PropertyId::MessageExpiryInterval, PropertyValue::FourByteInteger(v)) => {
187                    result.message_expiry_interval = Some(*v);
188                }
189                (PropertyId::ResponseTopic, PropertyValue::Utf8String(v)) => {
190                    result.response_topic = Some(v.clone());
191                }
192                (PropertyId::CorrelationData, PropertyValue::BinaryData(v)) => {
193                    result.correlation_data = Some(v.to_vec());
194                }
195                (PropertyId::UserProperty, PropertyValue::Utf8StringPair(k, v)) => {
196                    result.user_properties.push((k.clone(), v.clone()));
197                }
198                (PropertyId::SubscriptionIdentifier, PropertyValue::VariableByteInteger(v)) => {
199                    result.subscription_identifiers.push(*v);
200                }
201                (PropertyId::ContentType, PropertyValue::Utf8String(v)) => {
202                    result.content_type = Some(v.clone());
203                }
204                _ => {}
205            }
206        }
207
208        result
209    }
210}
211
212impl From<MessageProperties> for PublishProperties {
213    fn from(msg_props: MessageProperties) -> Self {
214        Self {
215            payload_format_indicator: msg_props.payload_format_indicator,
216            message_expiry_interval: msg_props.message_expiry_interval,
217            topic_alias: None,
218            response_topic: msg_props.response_topic,
219            correlation_data: msg_props.correlation_data,
220            user_properties: msg_props.user_properties,
221            subscription_identifiers: msg_props.subscription_identifiers,
222            content_type: msg_props.content_type,
223        }
224    }
225}