Skip to main content

rocketmq_model/common/message/
message_ext.rs

1// Copyright 2023 The RocketMQ Rust Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::any::Any;
16use std::collections::HashMap;
17use std::fmt;
18use std::net::SocketAddr;
19
20use bytes::Buf;
21use bytes::BufMut;
22use bytes::Bytes;
23use cheetah_string::CheetahString;
24
25use crate::common::message::message_single::Message;
26use crate::common::message::MessageTrait;
27use crate::common::sys_flag::message_sys_flag::MessageSysFlag;
28
29#[derive(Clone)]
30pub struct MessageExt {
31    pub message: Message,
32    pub broker_name: CheetahString,
33    pub queue_id: i32,
34    pub store_size: i32,
35    pub queue_offset: i64,
36    pub sys_flag: i32,
37    pub born_timestamp: i64,
38    pub born_host: SocketAddr,
39    pub store_timestamp: i64,
40    pub store_host: SocketAddr,
41    pub msg_id: CheetahString,
42    pub commit_log_offset: i64,
43    pub body_crc: u32,
44    pub reconsume_times: i32,
45    pub prepared_transaction_offset: i64,
46}
47
48impl MessageExt {
49    pub fn socket_address_2_byte_buffer(ip: &SocketAddr) -> bytes::Bytes {
50        match ip {
51            SocketAddr::V4(value) => {
52                let mut byte_buffer = bytes::BytesMut::with_capacity(4 + 4);
53                byte_buffer.put_slice(&value.ip().octets());
54                byte_buffer.put_i32(value.port() as i32);
55                byte_buffer.copy_to_bytes(byte_buffer.len())
56            }
57            SocketAddr::V6(value) => {
58                let mut byte_buffer = bytes::BytesMut::with_capacity(16 + 4);
59                byte_buffer.put_slice(&value.ip().octets());
60                byte_buffer.put_i32(value.port() as i32);
61                byte_buffer.copy_to_bytes(byte_buffer.len())
62            }
63        }
64    }
65
66    #[inline]
67    pub fn born_host_bytes(&self) -> bytes::Bytes {
68        Self::socket_address_2_byte_buffer(&self.born_host)
69    }
70
71    #[inline]
72    pub fn born_store_bytes(&self) -> bytes::Bytes {
73        Self::socket_address_2_byte_buffer(&self.store_host)
74    }
75
76    #[inline]
77    pub fn topic(&self) -> &CheetahString {
78        self.message.topic()
79    }
80
81    #[inline]
82    pub fn born_host(&self) -> SocketAddr {
83        self.born_host
84    }
85
86    #[inline]
87    pub fn store_host(&self) -> SocketAddr {
88        self.store_host
89    }
90
91    #[inline]
92    pub fn with_born_host_v6_flag(&mut self) {
93        self.sys_flag |= MessageSysFlag::BORNHOST_V6_FLAG;
94    }
95
96    #[inline]
97    pub fn with_store_host_v6_flag(&mut self) {
98        self.sys_flag |= MessageSysFlag::STOREHOSTADDRESS_V6_FLAG;
99    }
100
101    #[inline]
102    pub fn body(&self) -> Option<bytes::Bytes> {
103        self.message.body()
104    }
105
106    #[inline]
107    pub fn sys_flag(&self) -> i32 {
108        self.sys_flag
109    }
110
111    #[inline]
112    pub fn body_crc(&self) -> u32 {
113        self.body_crc
114    }
115
116    #[inline]
117    pub fn queue_id(&self) -> i32 {
118        self.queue_id
119    }
120
121    #[inline]
122    pub fn flag(&self) -> i32 {
123        self.message.flag()
124    }
125
126    #[inline]
127    pub fn message_inner(&self) -> &Message {
128        &self.message
129    }
130
131    #[inline]
132    pub fn broker_name(&self) -> &str {
133        &self.broker_name
134    }
135
136    #[inline]
137    pub fn store_size(&self) -> i32 {
138        self.store_size
139    }
140
141    #[inline]
142    pub fn queue_offset(&self) -> i64 {
143        self.queue_offset
144    }
145
146    #[inline]
147    pub fn born_timestamp(&self) -> i64 {
148        self.born_timestamp
149    }
150
151    #[inline]
152    pub fn store_timestamp(&self) -> i64 {
153        self.store_timestamp
154    }
155
156    #[inline]
157    pub fn msg_id(&self) -> &CheetahString {
158        &self.msg_id
159    }
160
161    #[inline]
162    pub fn commit_log_offset(&self) -> i64 {
163        self.commit_log_offset
164    }
165
166    #[inline]
167    pub fn reconsume_times(&self) -> i32 {
168        self.reconsume_times
169    }
170
171    #[inline]
172    pub fn prepared_transaction_offset(&self) -> i64 {
173        self.prepared_transaction_offset
174    }
175    #[inline]
176    pub fn set_message_inner(&mut self, message_inner: Message) {
177        self.message = message_inner;
178    }
179    #[inline]
180    pub fn set_broker_name(&mut self, broker_name: CheetahString) {
181        self.broker_name = broker_name;
182    }
183    #[inline]
184    pub fn set_queue_id(&mut self, queue_id: i32) {
185        self.queue_id = queue_id;
186    }
187    #[inline]
188    pub fn set_store_size(&mut self, store_size: i32) {
189        self.store_size = store_size;
190    }
191    #[inline]
192    pub fn set_queue_offset(&mut self, queue_offset: i64) {
193        self.queue_offset = queue_offset;
194    }
195    #[inline]
196    pub fn set_sys_flag(&mut self, sys_flag: i32) {
197        self.sys_flag = sys_flag;
198    }
199    #[inline]
200    pub fn set_born_timestamp(&mut self, born_timestamp: i64) {
201        self.born_timestamp = born_timestamp;
202    }
203    #[inline]
204    pub fn set_born_host(&mut self, born_host: SocketAddr) {
205        self.born_host = born_host;
206    }
207    #[inline]
208    pub fn set_store_timestamp(&mut self, store_timestamp: i64) {
209        self.store_timestamp = store_timestamp;
210    }
211    #[inline]
212    pub fn set_store_host(&mut self, store_host: SocketAddr) {
213        self.store_host = store_host;
214    }
215    #[inline]
216    pub fn set_msg_id(&mut self, msg_id: CheetahString) {
217        self.msg_id = msg_id;
218    }
219    #[inline]
220    pub fn set_commit_log_offset(&mut self, commit_log_offset: i64) {
221        self.commit_log_offset = commit_log_offset;
222    }
223    #[inline]
224    pub fn set_body_crc(&mut self, body_crc: u32) {
225        self.body_crc = body_crc;
226    }
227    #[inline]
228    pub fn set_reconsume_times(&mut self, reconsume_times: i32) {
229        self.reconsume_times = reconsume_times;
230    }
231    #[inline]
232    pub fn set_prepared_transaction_offset(&mut self, prepared_transaction_offset: i64) {
233        self.prepared_transaction_offset = prepared_transaction_offset;
234    }
235    #[inline]
236    pub fn properties(&self) -> &HashMap<CheetahString, CheetahString> {
237        self.message.properties().as_map()
238    }
239    #[inline]
240    pub fn get_tags(&self) -> Option<CheetahString> {
241        self.message.get_tags()
242    }
243}
244
245impl Default for MessageExt {
246    fn default() -> Self {
247        Self {
248            message: Message::default(),
249            broker_name: CheetahString::default(),
250            queue_id: 0,
251            store_size: 0,
252            queue_offset: 0,
253            sys_flag: 0,
254            born_timestamp: 0,
255            born_host: SocketAddr::from(([127, 0, 0, 1], 10911)),
256            store_timestamp: 0,
257            store_host: SocketAddr::from(([127, 0, 0, 1], 10911)),
258            msg_id: CheetahString::default(),
259            commit_log_offset: 0,
260            body_crc: 0,
261            reconsume_times: 0,
262            prepared_transaction_offset: 0,
263        }
264    }
265}
266
267impl fmt::Display for MessageExt {
268    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
269        write!(
270            f,
271            "MessageExt{{topic='{}', queueId={}, queueOffset={}, flag={}, sysFlag={}, bodyLen={}, propertyCount={}, \
272             msgId='{}', reconsumeTimes={}}}",
273            self.topic(),
274            self.queue_id,
275            self.queue_offset,
276            self.flag(),
277            self.sys_flag,
278            self.message.body_slice().len(),
279            self.message.properties().len(),
280            self.msg_id,
281            self.reconsume_times
282        )
283    }
284}
285
286impl fmt::Debug for MessageExt {
287    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288        f.debug_struct("MessageExt")
289            .field("topic", self.topic())
290            .field("queue_id", &self.queue_id)
291            .field("queue_offset", &self.queue_offset)
292            .field("flag", &self.flag())
293            .field("sys_flag", &self.sys_flag)
294            .field("body_len", &self.message.body_slice().len())
295            .field("property_count", &self.message.properties().len())
296            .field("msg_id", &self.msg_id)
297            .field("reconsume_times", &self.reconsume_times)
298            .finish()
299    }
300}
301impl MessageTrait for MessageExt {
302    fn put_property(&mut self, key: CheetahString, value: CheetahString) {
303        self.message.put_property(key, value);
304    }
305
306    fn clear_property(&mut self, name: &str) {
307        self.message.clear_property(name);
308    }
309
310    fn property(&self, name: &CheetahString) -> Option<CheetahString> {
311        self.message.get_property(name)
312    }
313
314    fn property_ref(&self, name: &CheetahString) -> Option<&CheetahString> {
315        self.message.property_ref(name)
316    }
317
318    fn topic(&self) -> &CheetahString {
319        self.message.topic()
320    }
321
322    fn set_topic(&mut self, topic: CheetahString) {
323        self.message.set_topic(topic);
324    }
325
326    fn get_flag(&self) -> i32 {
327        self.message.get_flag()
328    }
329
330    fn set_flag(&mut self, flag: i32) {
331        self.message.set_flag(flag);
332    }
333
334    fn get_body(&self) -> Option<&Bytes> {
335        self.message.get_body()
336    }
337
338    fn set_body(&mut self, body: Bytes) {
339        self.message.set_body(Some(body));
340    }
341
342    fn get_properties(&self) -> &HashMap<CheetahString, CheetahString> {
343        self.message.get_properties()
344    }
345
346    fn set_properties(&mut self, properties: HashMap<CheetahString, CheetahString>) {
347        self.message.set_properties(properties);
348    }
349
350    #[inline]
351    fn transaction_id(&self) -> Option<&CheetahString> {
352        MessageTrait::transaction_id(&self.message)
353    }
354
355    fn set_transaction_id(&mut self, transaction_id: CheetahString) {
356        self.message.set_transaction_id(transaction_id);
357    }
358
359    fn get_compressed_body_mut(&mut self) -> Option<&mut Bytes> {
360        self.message.get_compressed_body_mut()
361    }
362
363    fn get_compressed_body(&self) -> Option<&Bytes> {
364        self.message.get_compressed_body()
365    }
366
367    fn set_compressed_body_mut(&mut self, compressed_body: Bytes) {
368        self.message.set_compressed_body_mut(compressed_body);
369    }
370    #[inline]
371    fn take_body(&mut self) -> Option<Bytes> {
372        self.message.take_body()
373    }
374
375    fn as_any(&self) -> &dyn Any {
376        self
377    }
378
379    fn as_any_mut(&mut self) -> &mut dyn Any {
380        self
381    }
382}
383
384// Automatic deref to Message for convenient access
385impl std::ops::Deref for MessageExt {
386    type Target = Message;
387
388    fn deref(&self) -> &Self::Target {
389        &self.message
390    }
391}
392
393impl std::ops::DerefMut for MessageExt {
394    fn deref_mut(&mut self) -> &mut Self::Target {
395        &mut self.message
396    }
397}
398
399// Conversion to new MessageEnvelope type
400impl From<MessageExt> for crate::common::message::message_envelope::MessageEnvelope {
401    fn from(ext: MessageExt) -> Self {
402        use crate::common::message::message_envelope::MessageEnvelope;
403        use crate::common::message::routing_context::RoutingContext;
404        use crate::common::message::storage_metadata::StorageMetadata;
405
406        let routing = RoutingContext::new(ext.born_host, ext.born_timestamp, ext.sys_flag);
407
408        let storage = StorageMetadata::new(
409            ext.broker_name,
410            ext.queue_id,
411            ext.queue_offset,
412            ext.commit_log_offset,
413            ext.store_timestamp,
414            ext.store_host,
415            ext.store_size,
416        );
417
418        MessageEnvelope::new(
419            ext.message,
420            routing,
421            storage,
422            ext.msg_id,
423            ext.body_crc,
424            ext.reconsume_times,
425            ext.prepared_transaction_offset,
426        )
427    }
428}
429
430// Conversion from new MessageEnvelope type
431impl From<crate::common::message::message_envelope::MessageEnvelope> for MessageExt {
432    fn from(envelope: crate::common::message::message_envelope::MessageEnvelope) -> Self {
433        Self {
434            message: envelope.message().clone(),
435            broker_name: CheetahString::from_slice(envelope.broker_name()),
436            queue_id: envelope.queue_id(),
437            store_size: envelope.store_size(),
438            queue_offset: envelope.queue_offset(),
439            sys_flag: envelope.sys_flag(),
440            born_timestamp: envelope.born_timestamp(),
441            born_host: envelope.born_host(),
442            store_timestamp: envelope.store_timestamp(),
443            store_host: envelope.store_host(),
444            msg_id: envelope.msg_id().clone(),
445            commit_log_offset: envelope.commit_log_offset(),
446            body_crc: envelope.body_crc(),
447            reconsume_times: envelope.reconsume_times(),
448            prepared_transaction_offset: envelope.prepared_transaction_offset(),
449        }
450    }
451}
452
453#[cfg(test)]
454mod tests {
455    use cheetah_string::CheetahString;
456
457    use super::*;
458    use crate::common::message::MessageTrait;
459
460    #[test]
461    fn message_ext_message_trait_transaction_id_returns_cheetah_string_ref() {
462        let mut message_ext = MessageExt::default();
463        message_ext.set_transaction_id(CheetahString::from_static_str("tx-123"));
464
465        let transaction_id = <MessageExt as MessageTrait>::transaction_id(&message_ext);
466
467        assert_eq!(transaction_id, Some(&CheetahString::from_static_str("tx-123")));
468    }
469
470    #[test]
471    fn message_ext_display_contains_only_safe_metadata() {
472        let mut message_ext = MessageExt::default();
473        message_ext.set_broker_name(CheetahString::from_static_str("BrokerA"));
474        message_ext.set_queue_id(3);
475        message_ext.set_store_size(128);
476        message_ext.set_queue_offset(42);
477        message_ext.set_sys_flag(1);
478        message_ext.set_born_timestamp(10);
479        message_ext.set_store_timestamp(20);
480        message_ext.set_msg_id(CheetahString::from_static_str("MSGID"));
481        message_ext.set_commit_log_offset(1000);
482        message_ext.set_body_crc(99);
483        message_ext.set_reconsume_times(2);
484        message_ext.set_prepared_transaction_offset(7);
485        message_ext.set_topic(CheetahString::from_static_str("TopicA"));
486        message_ext.set_body(Bytes::from_static(&[1, 255]));
487
488        assert_eq!(
489            message_ext.to_string(),
490            "MessageExt{topic='TopicA', queueId=3, queueOffset=42, flag=0, sysFlag=1, bodyLen=2, propertyCount=0, \
491             msgId='MSGID', reconsumeTimes=2}"
492        );
493    }
494}