1use std::collections::HashMap;
16
17use cheetah_string::CheetahString;
18
19use crate::common::message::MessageConst;
20
21#[derive(Clone, Debug, Default)]
23pub struct MessageProperties {
24 inner: HashMap<CheetahString, CheetahString>,
25}
26
27impl MessageProperties {
28 pub fn new() -> Self {
30 Self::default()
31 }
32
33 #[inline]
35 pub fn get(&self, key: MessagePropertyKey) -> Option<&str> {
36 self.inner.get(key.as_str()).map(|s| s.as_str())
37 }
38
39 pub(crate) fn insert(&mut self, key: MessagePropertyKey, value: impl Into<CheetahString>) {
41 self.inner.insert(key.to_cheetah_string(), value.into());
42 }
43
44 #[inline]
46 pub fn as_map(&self) -> &HashMap<CheetahString, CheetahString> {
47 &self.inner
48 }
49
50 #[doc(hidden)]
52 #[inline]
53 pub fn as_map_mut(&mut self) -> &mut HashMap<CheetahString, CheetahString> {
54 &mut self.inner
55 }
56
57 #[inline]
59 pub fn from_map(map: HashMap<CheetahString, CheetahString>) -> Self {
60 Self { inner: map }
61 }
62
63 #[inline]
65 pub fn len(&self) -> usize {
66 self.inner.len()
67 }
68
69 #[inline]
71 pub fn is_empty(&self) -> bool {
72 self.inner.is_empty()
73 }
74
75 #[inline]
79 pub fn tags(&self) -> Option<&str> {
80 self.get(MessagePropertyKey::Tags)
81 }
82
83 pub fn keys(&self) -> Option<Vec<String>> {
85 self.get(MessagePropertyKey::Keys).map(|s| {
86 s.split(MessageConst::KEY_SEPARATOR)
87 .filter(|k| !k.is_empty())
88 .map(|k| k.to_string())
89 .collect()
90 })
91 }
92
93 pub fn delay_level(&self) -> Option<i32> {
95 self.get(MessagePropertyKey::DelayTimeLevel)
96 .and_then(|s| s.parse().ok())
97 }
98
99 pub fn delay_time_sec(&self) -> Option<u64> {
101 self.get(MessagePropertyKey::DelayTimeSec).and_then(|s| s.parse().ok())
102 }
103
104 pub fn delay_time_ms(&self) -> Option<u64> {
106 self.get(MessagePropertyKey::DelayTimeMs).and_then(|s| s.parse().ok())
107 }
108
109 pub fn deliver_time_ms(&self) -> Option<u64> {
111 self.get(MessagePropertyKey::DeliverTimeMs).and_then(|s| s.parse().ok())
112 }
113
114 pub fn buyer_id(&self) -> Option<&str> {
116 self.get(MessagePropertyKey::BuyerId)
117 }
118
119 pub fn wait_store_msg_ok(&self) -> bool {
121 self.get(MessagePropertyKey::WaitStoreMsgOk)
122 .map(|s| s.eq_ignore_ascii_case("true"))
123 .unwrap_or(true)
124 }
125
126 pub fn origin_message_id(&self) -> Option<&str> {
128 self.get(MessagePropertyKey::OriginMessageId)
129 }
130
131 pub fn retry_topic(&self) -> Option<&str> {
133 self.get(MessagePropertyKey::RetryTopic)
134 }
135
136 pub fn real_topic(&self) -> Option<&str> {
138 self.get(MessagePropertyKey::RealTopic)
139 }
140
141 pub fn real_queue_id(&self) -> Option<i32> {
143 self.get(MessagePropertyKey::RealQueueId).and_then(|s| s.parse().ok())
144 }
145
146 pub fn unique_client_msg_id(&self) -> Option<&str> {
148 self.get(MessagePropertyKey::UniqueClientMsgId)
149 }
150
151 pub fn producer_group(&self) -> Option<&str> {
153 self.get(MessagePropertyKey::ProducerGroup)
154 }
155
156 pub fn instance_id(&self) -> Option<&str> {
158 self.get(MessagePropertyKey::InstanceId)
159 }
160
161 pub fn correlation_id(&self) -> Option<&str> {
163 self.get(MessagePropertyKey::CorrelationId)
164 }
165
166 pub fn message_type(&self) -> Option<&str> {
168 self.get(MessagePropertyKey::MessageType)
169 }
170
171 pub fn trace_switch(&self) -> bool {
173 self.get(MessagePropertyKey::TraceSwitch)
174 .map(|s| s == "true")
175 .unwrap_or(false)
176 }
177
178 pub fn priority(&self) -> i32 {
180 self.get(MessagePropertyKey::Priority)
181 .and_then(|s| s.parse().ok())
182 .unwrap_or(-1)
183 }
184}
185
186#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
188pub enum MessagePropertyKey {
189 Tags,
190 Keys,
191 WaitStoreMsgOk,
192 DelayTimeLevel,
193 DelayTimeSec,
194 DelayTimeMs,
195 DeliverTimeMs,
196 RetryTopic,
197 RealTopic,
198 RealQueueId,
199 TransactionPrepared,
200 ProducerGroup,
201 MinOffset,
202 MaxOffset,
203 BuyerId,
204 OriginGroup,
205 OriginMessageId,
206 TransferFlag,
207 CorrectionFlag,
208 MqReplyTopic,
209 MqReplyQueueId,
210 UniqueClientMsgId,
211 ReconsumeTime,
212 MsgRegion,
213 TraceSwitch,
214 UniqueKey,
215 MaxReconsumeTimes,
216 ConsumeStartTimestamp,
217 PopCk,
218 PopCkOffset,
219 FirstPopTime,
220 Priority,
221 TransactionPreparedQueueOffset,
222 DupInfo,
223 ExtendUniqInfo,
224 InstanceId,
225 CorrelationId,
226 MessageReplyToClient,
227 MessageTtl,
228 ReplyMessageArriveTime,
229 PushReplyTime,
230 Cluster,
231 MessageType,
232 InnerMultiQueueOffset,
233 TimerDelayLevel,
234 TimerEnqueueMs,
235 TimerDequeueMs,
236 TimerRollTimes,
237 TimerRollLabel,
238 TimerOutMs,
239 TimerDelUniqkey,
240 TimerOriginalDeliverMs,
241 TimerDeliveryToken,
242 TimerId,
243 TimerOwnerEpoch,
244 TimerLane,
245 TimerGeneration,
246 TimerEngineType,
247 TimerFormatVersion,
248 TimerPolicyFingerprint,
249 BornHost,
250 BornTimestamp,
251 DlqOriginTopic,
252 DlqOriginMessageId,
253 Crc32,
254 Redirect,
255 ForwardQueueId,
256 InnerBase,
257 InnerMultiDispatch,
258 InnerNum,
259 Mq2Flag,
260 TransOffset,
261 ShardingKey,
262 TransactionId,
263 TransactionCheckTimes,
264 TransientGroupConfig,
265 TransientTopicConfig,
266 TraceContext,
267}
268
269impl MessagePropertyKey {
270 pub fn as_str(&self) -> &'static str {
272 match self {
273 Self::Tags => MessageConst::PROPERTY_TAGS,
274 Self::Keys => MessageConst::PROPERTY_KEYS,
275 Self::WaitStoreMsgOk => MessageConst::PROPERTY_WAIT_STORE_MSG_OK,
276 Self::DelayTimeLevel => MessageConst::PROPERTY_DELAY_TIME_LEVEL,
277 Self::DelayTimeSec => MessageConst::PROPERTY_TIMER_DELAY_SEC,
278 Self::DelayTimeMs => MessageConst::PROPERTY_TIMER_DELAY_MS,
279 Self::DeliverTimeMs => MessageConst::PROPERTY_TIMER_DELIVER_MS,
280 Self::RetryTopic => MessageConst::PROPERTY_RETRY_TOPIC,
281 Self::RealTopic => MessageConst::PROPERTY_REAL_TOPIC,
282 Self::RealQueueId => MessageConst::PROPERTY_REAL_QUEUE_ID,
283 Self::TransactionPrepared => MessageConst::PROPERTY_TRANSACTION_PREPARED,
284 Self::ProducerGroup => MessageConst::PROPERTY_PRODUCER_GROUP,
285 Self::MinOffset => MessageConst::PROPERTY_MIN_OFFSET,
286 Self::MaxOffset => MessageConst::PROPERTY_MAX_OFFSET,
287 Self::BuyerId => MessageConst::PROPERTY_BUYER_ID,
288 Self::OriginGroup => MessageConst::PROPERTY_ORIGIN_GROUP,
289 Self::OriginMessageId => MessageConst::PROPERTY_ORIGIN_MESSAGE_ID,
290 Self::TransferFlag => MessageConst::PROPERTY_TRANSFER_FLAG,
291 Self::CorrectionFlag => MessageConst::PROPERTY_CORRECTION_FLAG,
292 Self::MqReplyTopic => MessageConst::PROPERTY_MESSAGE_REPLY_TO_CLIENT,
293 Self::MqReplyQueueId => MessageConst::PROPERTY_MESSAGE_REPLY_TO_CLIENT,
294 Self::UniqueClientMsgId => MessageConst::PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX,
295 Self::ReconsumeTime => MessageConst::PROPERTY_RECONSUME_TIME,
296 Self::MsgRegion => MessageConst::PROPERTY_MSG_REGION,
297 Self::TraceSwitch => MessageConst::PROPERTY_TRACE_SWITCH,
298 Self::UniqueKey => MessageConst::PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX,
299 Self::MaxReconsumeTimes => MessageConst::PROPERTY_MAX_RECONSUME_TIMES,
300 Self::ConsumeStartTimestamp => MessageConst::PROPERTY_CONSUME_START_TIMESTAMP,
301 Self::PopCk => MessageConst::PROPERTY_POP_CK,
302 Self::PopCkOffset => MessageConst::PROPERTY_POP_CK_OFFSET,
303 Self::FirstPopTime => MessageConst::PROPERTY_FIRST_POP_TIME,
304 Self::Priority => MessageConst::PROPERTY_PRIORITY,
305 Self::TransactionPreparedQueueOffset => MessageConst::PROPERTY_TRANSACTION_PREPARED_QUEUE_OFFSET,
306 Self::DupInfo => MessageConst::DUP_INFO,
307 Self::ExtendUniqInfo => MessageConst::PROPERTY_EXTEND_UNIQ_INFO,
308 Self::InstanceId => MessageConst::PROPERTY_INSTANCE_ID,
309 Self::CorrelationId => MessageConst::PROPERTY_CORRELATION_ID,
310 Self::MessageReplyToClient => MessageConst::PROPERTY_MESSAGE_REPLY_TO_CLIENT,
311 Self::MessageTtl => MessageConst::PROPERTY_MESSAGE_TTL,
312 Self::ReplyMessageArriveTime => MessageConst::PROPERTY_REPLY_MESSAGE_ARRIVE_TIME,
313 Self::PushReplyTime => MessageConst::PROPERTY_PUSH_REPLY_TIME,
314 Self::Cluster => MessageConst::PROPERTY_CLUSTER,
315 Self::MessageType => MessageConst::PROPERTY_MESSAGE_TYPE,
316 Self::InnerMultiQueueOffset => MessageConst::PROPERTY_INNER_MULTI_QUEUE_OFFSET,
317 Self::TimerDelayLevel => MessageConst::PROPERTY_TIMER_DELAY_LEVEL,
318 Self::TimerEnqueueMs => MessageConst::PROPERTY_TIMER_ENQUEUE_MS,
319 Self::TimerDequeueMs => MessageConst::PROPERTY_TIMER_DEQUEUE_MS,
320 Self::TimerRollTimes => MessageConst::PROPERTY_TIMER_ROLL_TIMES,
321 Self::TimerRollLabel => MessageConst::PROPERTY_TIMER_ROLL_LABEL,
322 Self::TimerOutMs => MessageConst::PROPERTY_TIMER_OUT_MS,
323 Self::TimerDelUniqkey => MessageConst::PROPERTY_TIMER_DEL_UNIQKEY,
324 Self::TimerOriginalDeliverMs => MessageConst::PROPERTY_TIMER_ORIGINAL_DELIVER_MS,
325 Self::TimerDeliveryToken => MessageConst::PROPERTY_TIMER_DELIVERY_TOKEN,
326 Self::TimerId => MessageConst::PROPERTY_TIMER_ID,
327 Self::TimerOwnerEpoch => MessageConst::PROPERTY_TIMER_OWNER_EPOCH,
328 Self::TimerLane => MessageConst::PROPERTY_TIMER_LANE,
329 Self::TimerGeneration => MessageConst::PROPERTY_TIMER_GENERATION,
330 Self::TimerEngineType => MessageConst::TIMER_ENGINE_TYPE,
331 Self::TimerFormatVersion => MessageConst::PROPERTY_TIMER_FORMAT_VERSION,
332 Self::TimerPolicyFingerprint => MessageConst::PROPERTY_TIMER_POLICY_FINGERPRINT,
333 Self::BornHost => MessageConst::PROPERTY_BORN_HOST,
334 Self::BornTimestamp => MessageConst::PROPERTY_BORN_TIMESTAMP,
335 Self::DlqOriginTopic => MessageConst::PROPERTY_DLQ_ORIGIN_TOPIC,
336 Self::DlqOriginMessageId => MessageConst::PROPERTY_DLQ_ORIGIN_MESSAGE_ID,
337 Self::Crc32 => MessageConst::PROPERTY_CRC32,
338 Self::Redirect => MessageConst::PROPERTY_REDIRECT,
339 Self::ForwardQueueId => MessageConst::PROPERTY_FORWARD_QUEUE_ID,
340 Self::InnerBase => MessageConst::PROPERTY_INNER_BASE,
341 Self::InnerMultiDispatch => MessageConst::PROPERTY_INNER_MULTI_DISPATCH,
342 Self::InnerNum => MessageConst::PROPERTY_INNER_NUM,
343 Self::Mq2Flag => MessageConst::PROPERTY_MQ2_FLAG,
344 Self::TransOffset => MessageConst::PROPERTY_TRANS_OFFSET,
345 Self::ShardingKey => MessageConst::PROPERTY_SHARDING_KEY,
346 Self::TransactionId => MessageConst::PROPERTY_TRANSACTION_ID,
347 Self::TransactionCheckTimes => MessageConst::PROPERTY_TRANSACTION_CHECK_TIMES,
348 Self::TransientGroupConfig => MessageConst::PROPERTY_TRANSIENT_GROUP_CONFIG,
349 Self::TransientTopicConfig => MessageConst::PROPERTY_TRANSIENT_TOPIC_CONFIG,
350 Self::TraceContext => MessageConst::PROPERTY_TRACE_CONTEXT,
351 }
352 }
353
354 pub(crate) fn to_cheetah_string(self) -> CheetahString {
355 CheetahString::from_static_str(self.as_str())
356 }
357}
358
359#[cfg(test)]
360mod tests {
361 use super::*;
362
363 #[test]
364 fn wait_store_msg_ok_matches_java_boolean_parse_semantics() {
365 let mut properties = MessageProperties::new();
366 assert!(properties.wait_store_msg_ok());
367
368 properties.insert(MessagePropertyKey::WaitStoreMsgOk, "true");
369 assert!(properties.wait_store_msg_ok());
370
371 properties.insert(MessagePropertyKey::WaitStoreMsgOk, "TRUE");
372 assert!(properties.wait_store_msg_ok());
373
374 properties.insert(MessagePropertyKey::WaitStoreMsgOk, "false");
375 assert!(!properties.wait_store_msg_ok());
376
377 properties.insert(MessagePropertyKey::WaitStoreMsgOk, "yes");
378 assert!(!properties.wait_store_msg_ok());
379 }
380
381 #[test]
382 fn priority_matches_java_default_and_parse_semantics() {
383 let mut properties = MessageProperties::new();
384 assert_eq!(properties.priority(), -1);
385
386 properties.insert(MessagePropertyKey::Priority, "7");
387 assert_eq!(properties.priority(), 7);
388
389 properties.insert(MessagePropertyKey::Priority, "invalid");
390 assert_eq!(properties.priority(), -1);
391 }
392
393 #[test]
394 fn protocol_property_keys_include_java_message_const_gaps() {
395 assert_eq!(MessagePropertyKey::OriginGroup.as_str(), "ORIGIN_GROUP");
396 assert_eq!(MessagePropertyKey::TransOffset.as_str(), "TRANS_OFFSET");
397 assert_eq!(MessagePropertyKey::TimerRollLabel.as_str(), "TIMER_ROLL_LABEL");
398 }
399}