rocketmq_client_rust/hook/
consume_message_context.rs1use std::any::Any;
16use std::collections::HashMap;
17use std::fmt;
18use std::sync::Arc;
19
20use cheetah_string::CheetahString;
21use rocketmq_model::common::message::message_ext::MessageExt;
22use rocketmq_model::common::message::message_queue::MessageQueue;
23
24use crate::base::access_channel::AccessChannel;
25
26#[derive(Default)]
45pub struct ConsumeMessageContext<'a> {
46 pub consumer_group: CheetahString,
48 pub msg_list: &'a [Arc<MessageExt>],
50 pub mq: Option<MessageQueue>,
52 pub success: bool,
54 pub status: CheetahString,
56 pub mq_trace_context: Option<Arc<dyn Any + Send + Sync>>,
58 pub props: HashMap<CheetahString, CheetahString>,
60 pub namespace: CheetahString,
62 pub access_channel: Option<AccessChannel>,
64}
65
66impl<'a> ConsumeMessageContext<'a> {
67 #[inline]
69 pub fn new(consumer_group: CheetahString, msg_list: &'a [Arc<MessageExt>]) -> Self {
70 Self {
71 consumer_group,
72 msg_list,
73 ..Default::default()
74 }
75 }
76
77 #[inline]
79 pub fn with_mq(mut self, mq: MessageQueue) -> Self {
80 self.mq = Some(mq);
81 self
82 }
83
84 #[inline]
86 pub fn with_success(mut self, success: bool) -> Self {
87 self.success = success;
88 self
89 }
90
91 #[inline]
93 pub fn with_status(mut self, status: impl Into<CheetahString>) -> Self {
94 self.status = status.into();
95 self
96 }
97
98 #[inline]
100 pub fn with_trace_context(mut self, context: Arc<dyn Any + Send + Sync>) -> Self {
101 self.mq_trace_context = Some(context);
102 self
103 }
104
105 #[inline]
107 pub fn with_namespace(mut self, namespace: impl Into<CheetahString>) -> Self {
108 self.namespace = namespace.into();
109 self
110 }
111
112 #[inline]
114 pub fn with_access_channel(mut self, channel: AccessChannel) -> Self {
115 self.access_channel = Some(channel);
116 self
117 }
118
119 #[inline]
121 pub fn add_prop(&mut self, key: impl Into<CheetahString>, value: impl Into<CheetahString>) {
122 self.props.insert(key.into(), value.into());
123 }
124
125 #[inline]
127 pub fn message_count(&self) -> usize {
128 self.msg_list.len()
129 }
130}
131
132impl<'a> fmt::Display for ConsumeMessageContext<'a> {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 write!(
135 f,
136 "ConsumeMessageContext {{ consumer_group: {}, msg_count: {}, ",
137 self.consumer_group,
138 self.msg_list.len()
139 )?;
140
141 if let Some(ref mq) = self.mq {
142 write!(f, "mq: {}, ", mq)?;
143 }
144
145 write!(f, "success: {}, status: {}", self.success, self.status)?;
146
147 if !self.namespace.is_empty() {
148 write!(f, ", namespace: {}", self.namespace)?;
149 }
150
151 if let Some(ref channel) = self.access_channel {
152 write!(f, ", access_channel: {:?}", channel)?;
153 }
154
155 write!(f, " }}")
156 }
157}
158
159impl<'a> fmt::Debug for ConsumeMessageContext<'a> {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 f.debug_struct("ConsumeMessageContext")
162 .field("consumer_group", &self.consumer_group)
163 .field("msg_list_len", &self.msg_list.len())
164 .field("mq", &self.mq)
165 .field("success", &self.success)
166 .field("status", &self.status)
167 .field("mq_trace_context", &self.mq_trace_context.as_ref().map(|_| "Some(_)"))
168 .field("props_count", &self.props.len())
169 .field("namespace", &self.namespace)
170 .field("access_channel", &self.access_channel)
171 .finish()
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178
179 #[test]
180 fn consume_message_context_new() {
181 let group = CheetahString::from("test_group");
182 let msg_list = vec![Arc::new(MessageExt::default())];
183 let context = ConsumeMessageContext::new(group.clone(), &msg_list);
184
185 assert_eq!(context.consumer_group, group);
186 assert_eq!(context.message_count(), 1);
187 assert!(context.mq.is_none());
188 assert!(!context.success);
189 }
190
191 #[test]
192 fn consume_message_context_builder_methods() {
193 let group = CheetahString::from("test_group");
194 let msg_list = vec![];
195 let mq = MessageQueue::from_parts("topic", "broker", 1);
196
197 let context = ConsumeMessageContext::new(group, &msg_list)
198 .with_mq(mq.clone())
199 .with_success(true)
200 .with_status("SUCCESS")
201 .with_namespace("test_ns")
202 .with_access_channel(AccessChannel::Cloud);
203
204 assert_eq!(context.mq.unwrap(), mq);
205 assert!(context.success);
206 assert_eq!(context.status, "SUCCESS");
207 assert_eq!(context.namespace, "test_ns");
208 assert_eq!(context.access_channel.unwrap(), AccessChannel::Cloud);
209 }
210
211 #[test]
212 fn consume_message_context_add_prop() {
213 let mut context = ConsumeMessageContext::<'static>::default();
214 context.add_prop("key1", "value1");
215 assert_eq!(context.props.get(&CheetahString::from("key1")).unwrap(), "value1");
216 }
217
218 #[test]
219 fn consume_message_context_display() {
220 let group = CheetahString::from("test_group");
221 let msg_list = vec![];
222 let context = ConsumeMessageContext::new(group, &msg_list)
223 .with_success(true)
224 .with_status("OK");
225
226 let display = format!("{}", context);
227 assert!(display.contains("consumer_group: test_group"));
228 assert!(display.contains("msg_count: 0"));
229 assert!(display.contains("success: true"));
230 assert!(display.contains("status: OK"));
231 }
232
233 #[test]
234 fn consume_message_context_debug() {
235 let context = ConsumeMessageContext::<'static>::default();
236 let debug = format!("{:?}", context);
237 assert!(debug.contains("ConsumeMessageContext"));
238 assert!(debug.contains("consumer_group"));
239 }
240
241 #[test]
242 fn consume_message_context_with_trace_context() {
243 let context =
244 ConsumeMessageContext::<'static>::default().with_trace_context(Arc::new("trace_data".to_string()));
245 assert!(context.mq_trace_context.is_some());
246 }
247}