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}