use std::any::Any;
use std::collections::HashMap;
use std::fmt;
use std::sync::Arc;
use cheetah_string::CheetahString;
use rocketmq_model::common::message::message_ext::MessageExt;
use rocketmq_model::common::message::message_queue::MessageQueue;
use crate::base::access_channel::AccessChannel;
#[derive(Default)]
pub struct ConsumeMessageContext<'a> {
pub consumer_group: CheetahString,
pub msg_list: &'a [Arc<MessageExt>],
pub mq: Option<MessageQueue>,
pub success: bool,
pub status: CheetahString,
pub mq_trace_context: Option<Arc<dyn Any + Send + Sync>>,
pub props: HashMap<CheetahString, CheetahString>,
pub namespace: CheetahString,
pub access_channel: Option<AccessChannel>,
}
impl<'a> ConsumeMessageContext<'a> {
#[inline]
pub fn new(consumer_group: CheetahString, msg_list: &'a [Arc<MessageExt>]) -> Self {
Self {
consumer_group,
msg_list,
..Default::default()
}
}
#[inline]
pub fn with_mq(mut self, mq: MessageQueue) -> Self {
self.mq = Some(mq);
self
}
#[inline]
pub fn with_success(mut self, success: bool) -> Self {
self.success = success;
self
}
#[inline]
pub fn with_status(mut self, status: impl Into<CheetahString>) -> Self {
self.status = status.into();
self
}
#[inline]
pub fn with_trace_context(mut self, context: Arc<dyn Any + Send + Sync>) -> Self {
self.mq_trace_context = Some(context);
self
}
#[inline]
pub fn with_namespace(mut self, namespace: impl Into<CheetahString>) -> Self {
self.namespace = namespace.into();
self
}
#[inline]
pub fn with_access_channel(mut self, channel: AccessChannel) -> Self {
self.access_channel = Some(channel);
self
}
#[inline]
pub fn add_prop(&mut self, key: impl Into<CheetahString>, value: impl Into<CheetahString>) {
self.props.insert(key.into(), value.into());
}
#[inline]
pub fn message_count(&self) -> usize {
self.msg_list.len()
}
}
impl<'a> fmt::Display for ConsumeMessageContext<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"ConsumeMessageContext {{ consumer_group: {}, msg_count: {}, ",
self.consumer_group,
self.msg_list.len()
)?;
if let Some(ref mq) = self.mq {
write!(f, "mq: {}, ", mq)?;
}
write!(f, "success: {}, status: {}", self.success, self.status)?;
if !self.namespace.is_empty() {
write!(f, ", namespace: {}", self.namespace)?;
}
if let Some(ref channel) = self.access_channel {
write!(f, ", access_channel: {:?}", channel)?;
}
write!(f, " }}")
}
}
impl<'a> fmt::Debug for ConsumeMessageContext<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ConsumeMessageContext")
.field("consumer_group", &self.consumer_group)
.field("msg_list_len", &self.msg_list.len())
.field("mq", &self.mq)
.field("success", &self.success)
.field("status", &self.status)
.field("mq_trace_context", &self.mq_trace_context.as_ref().map(|_| "Some(_)"))
.field("props_count", &self.props.len())
.field("namespace", &self.namespace)
.field("access_channel", &self.access_channel)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn consume_message_context_new() {
let group = CheetahString::from("test_group");
let msg_list = vec![Arc::new(MessageExt::default())];
let context = ConsumeMessageContext::new(group.clone(), &msg_list);
assert_eq!(context.consumer_group, group);
assert_eq!(context.message_count(), 1);
assert!(context.mq.is_none());
assert!(!context.success);
}
#[test]
fn consume_message_context_builder_methods() {
let group = CheetahString::from("test_group");
let msg_list = vec![];
let mq = MessageQueue::from_parts("topic", "broker", 1);
let context = ConsumeMessageContext::new(group, &msg_list)
.with_mq(mq.clone())
.with_success(true)
.with_status("SUCCESS")
.with_namespace("test_ns")
.with_access_channel(AccessChannel::Cloud);
assert_eq!(context.mq.unwrap(), mq);
assert!(context.success);
assert_eq!(context.status, "SUCCESS");
assert_eq!(context.namespace, "test_ns");
assert_eq!(context.access_channel.unwrap(), AccessChannel::Cloud);
}
#[test]
fn consume_message_context_add_prop() {
let mut context = ConsumeMessageContext::<'static>::default();
context.add_prop("key1", "value1");
assert_eq!(context.props.get(&CheetahString::from("key1")).unwrap(), "value1");
}
#[test]
fn consume_message_context_display() {
let group = CheetahString::from("test_group");
let msg_list = vec![];
let context = ConsumeMessageContext::new(group, &msg_list)
.with_success(true)
.with_status("OK");
let display = format!("{}", context);
assert!(display.contains("consumer_group: test_group"));
assert!(display.contains("msg_count: 0"));
assert!(display.contains("success: true"));
assert!(display.contains("status: OK"));
}
#[test]
fn consume_message_context_debug() {
let context = ConsumeMessageContext::<'static>::default();
let debug = format!("{:?}", context);
assert!(debug.contains("ConsumeMessageContext"));
assert!(debug.contains("consumer_group"));
}
#[test]
fn consume_message_context_with_trace_context() {
let context =
ConsumeMessageContext::<'static>::default().with_trace_context(Arc::new("trace_data".to_string()));
assert!(context.mq_trace_context.is_some());
}
}