1use crate::error::MqError;
2use async_trait::async_trait;
3use serde::{Deserialize, Serialize};
4use std::collections::{HashMap, VecDeque};
5use std::sync::Arc;
6use tokio::sync::RwLock;
7
8#[async_trait]
9pub trait MessageQueue: Send + Sync {
10 async fn publish(&self, topic: &str, message: &[u8]) -> Result<(), MqError>;
11 async fn consume(&self, topic: &str) -> Result<Option<Message>, MqError>;
12 async fn ack(&self, message_id: &str) -> Result<(), MqError>;
13 async fn subscribe(&self, topic: &str) -> Result<(), MqError>;
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct Message {
18 pub topic: String,
19 pub payload: Vec<u8>,
20 pub key: Option<String>,
21 pub timestamp: i64,
22 pub headers: HashMap<String, String>,
23 #[serde(default)]
24 pub id: String,
25}
26
27impl Message {
28 pub fn new(topic: impl Into<String>, payload: Vec<u8>) -> Self {
29 Self {
30 topic: topic.into(),
31 payload,
32 key: None,
33 timestamp: current_timestamp(),
34 headers: HashMap::new(),
35 id: String::new(),
36 }
37 }
38
39 pub fn with_key(mut self, key: impl Into<String>) -> Self {
40 self.key = Some(key.into());
41 self
42 }
43
44 pub fn text(&self) -> Option<&str> {
45 std::str::from_utf8(&self.payload).ok()
46 }
47
48 pub fn json<T: serde::de::DeserializeOwned>(&self) -> Option<T> {
49 serde_json::from_slice(&self.payload).ok()
50 }
51
52 pub fn text_message(topic: impl Into<String>, text: impl Into<String>) -> Self {
53 Self::new(topic, text.into().into_bytes())
54 }
55
56 pub fn json_message<T: serde::Serialize>(
57 topic: impl Into<String>,
58 data: &T,
59 ) -> Result<Self, MqError> {
60 let payload = serde_json::to_vec(data)?;
61 Ok(Self::new(topic, payload))
62 }
63}
64
65fn current_timestamp() -> i64 {
71 use std::time::{SystemTime, UNIX_EPOCH};
72 match SystemTime::now().duration_since(UNIX_EPOCH) {
73 Ok(d) => d.as_millis() as i64,
74 Err(e) => {
75 eprintln!(
78 "WARN: current_timestamp: system time before UNIX_EPOCH: {} (duration_secs={})",
79 e,
80 e.duration().as_secs()
81 );
82 0
83 }
84 }
85}
86
87pub struct QueueConfig {
88 pub provider: MqProvider,
89 pub brokers: Vec<String>,
90 pub group_id: Option<String>,
91 pub username: Option<String>,
92 pub password: Option<String>,
93}
94
95impl Default for QueueConfig {
96 fn default() -> Self {
97 Self {
98 provider: MqProvider::Kafka(KafkaConfig::default()),
99 brokers: vec!["localhost:9092".to_string()],
100 group_id: None,
101 username: None,
102 password: None,
103 }
104 }
105}
106
107impl QueueConfig {
108 pub fn new() -> Self {
109 Self::default()
110 }
111
112 pub fn with_provider(mut self, provider: MqProvider) -> Self {
113 self.provider = provider;
114 self
115 }
116
117 pub fn with_brokers(mut self, brokers: Vec<String>) -> Self {
118 self.brokers = brokers;
119 self
120 }
121
122 pub fn with_group(mut self, group: impl Into<String>) -> Self {
123 self.group_id = Some(group.into());
124 self
125 }
126
127 pub fn with_auth(mut self, username: impl Into<String>, password: impl Into<String>) -> Self {
128 self.username = Some(username.into());
129 self.password = Some(password.into());
130 self
131 }
132}
133
134#[derive(Debug, Clone)]
135pub enum MqProvider {
136 Kafka(KafkaConfig),
137 RabbitMQ(RabbitConfig),
138 RocketMQ(RocketConfig),
139 ActiveMQ(ActiveConfig),
140 Nats(NatsConfig),
141 Pulsar(PulsarConfig),
142}
143
144#[derive(Debug, Clone, Default)]
145pub struct KafkaConfig {
146 pub client_id: Option<String>,
147 pub acks: Option<String>,
148 pub retries: Option<u32>,
149}
150
151#[derive(Debug, Clone, Default)]
152pub struct RabbitConfig {
153 pub virtual_host: Option<String>,
154}
155
156#[derive(Debug, Clone, Default)]
157pub struct RocketConfig {
158 pub namespace: Option<String>,
159}
160
161#[derive(Debug, Clone, Default)]
162pub struct ActiveConfig {
163 pub broker_url: Option<String>,
164}
165
166#[derive(Debug, Clone, Default)]
167pub struct NatsConfig {
168 pub name: Option<String>,
169}
170
171#[derive(Debug, Clone, Default)]
172pub struct PulsarConfig {
173 pub service_url: Option<String>,
174}
175
176pub struct InMemoryQueue {
177 inner: Arc<RwLock<InMemoryQueueInner>>,
178}
179
180struct InMemoryQueueInner {
181 queues: HashMap<String, VecDeque<Message>>,
182 in_flight: HashMap<String, Message>,
183 subscribers: HashMap<String, usize>,
184 next_id: u64,
185 max_messages_per_topic: usize,
188}
189
190const DEFAULT_MAX_MESSAGES_PER_TOPIC: usize = 100_000;
192
193impl InMemoryQueue {
194 pub fn new() -> Self {
195 Self::with_max_messages_per_topic(DEFAULT_MAX_MESSAGES_PER_TOPIC)
196 }
197
198 pub fn with_max_messages_per_topic(max: usize) -> Self {
203 Self {
204 inner: Arc::new(RwLock::new(InMemoryQueueInner {
205 queues: HashMap::new(),
206 in_flight: HashMap::new(),
207 subscribers: HashMap::new(),
208 next_id: 1,
209 max_messages_per_topic: max,
210 })),
211 }
212 }
213
214 pub async fn message_count(&self, topic: &str) -> usize {
215 let inner = self.inner.read().await;
216 inner.queues.get(topic).map(|q| q.len()).unwrap_or(0)
217 }
218
219 pub async fn subscriber_count(&self, topic: &str) -> usize {
220 let inner = self.inner.read().await;
221 *inner.subscribers.get(topic).unwrap_or(&0)
222 }
223
224 pub async fn in_flight_count(&self) -> usize {
225 let inner = self.inner.read().await;
226 inner.in_flight.len()
227 }
228}
229
230impl Default for InMemoryQueue {
231 fn default() -> Self {
232 Self::new()
233 }
234}
235
236#[async_trait]
237impl MessageQueue for InMemoryQueue {
238 async fn publish(&self, topic: &str, message: &[u8]) -> Result<(), MqError> {
239 let mut inner = self.inner.write().await;
240 let current_count = inner.queues.get(topic).map(|q| q.len()).unwrap_or(0);
242 if current_count >= inner.max_messages_per_topic {
243 return Err(MqError::Publish(format!(
244 "topic '{}' is full: {} >= {} messages (H-3 protection)",
245 topic, current_count, inner.max_messages_per_topic
246 )));
247 }
248 let id = format!("msg-{}", inner.next_id);
249 inner.next_id = inner
252 .next_id
253 .checked_add(1)
254 .ok_or_else(|| MqError::Publish("message id overflow: u64::MAX reached".to_string()))?;
255 let msg = Message {
256 id,
257 ..Message::new(topic, message.to_vec())
258 };
259 inner
260 .queues
261 .entry(topic.to_string())
262 .or_insert_with(VecDeque::new)
263 .push_back(msg);
264 Ok(())
265 }
266
267 async fn consume(&self, topic: &str) -> Result<Option<Message>, MqError> {
268 let mut inner = self.inner.write().await;
269 let queue = inner
270 .queues
271 .entry(topic.to_string())
272 .or_insert_with(VecDeque::new);
273 if let Some(msg) = queue.pop_front() {
274 inner.in_flight.insert(msg.id.clone(), msg.clone());
275 Ok(Some(msg))
276 } else {
277 Ok(None)
278 }
279 }
280
281 async fn ack(&self, message_id: &str) -> Result<(), MqError> {
282 let mut inner = self.inner.write().await;
283 inner.in_flight.remove(message_id).ok_or_else(|| {
284 MqError::NotSupported(format!("Message not found for ack: {}", message_id))
285 })?;
286 Ok(())
287 }
288
289 async fn subscribe(&self, topic: &str) -> Result<(), MqError> {
290 let mut inner = self.inner.write().await;
291 *inner.subscribers.entry(topic.to_string()).or_insert(0) += 1;
292 Ok(())
293 }
294}
295
296pub struct QueueWrapper {
297 queue: Box<dyn MessageQueue>,
298}
299
300impl QueueWrapper {
301 pub fn new(provider: MqProvider) -> Self {
302 let queue: Box<dyn MessageQueue> = match provider {
303 MqProvider::Kafka(_) => Box::new(crate::kafka::InMemoryKafkaQueue::new()),
304 MqProvider::RabbitMQ(_) => Box::new(crate::rabbitmq::InMemoryRabbitmqQueue::new()),
305 MqProvider::RocketMQ(_) => Box::new(crate::rocketmq::InMemoryRocketmqQueue::new()),
306 MqProvider::ActiveMQ(_) => Box::new(crate::activemq::InMemoryActivemqQueue::new()),
307 MqProvider::Nats(_) => Box::new(crate::nats::InMemoryNatsQueue::new()),
308 MqProvider::Pulsar(_) => Box::new(crate::pulsar::InMemoryPulsarQueue::new()),
309 };
310 Self { queue }
311 }
312
313 pub async fn publish(&self, topic: &str, message: &[u8]) -> Result<(), MqError> {
314 self.queue.publish(topic, message).await
315 }
316
317 pub async fn consume(&self, topic: &str) -> Result<Option<Message>, MqError> {
318 self.queue.consume(topic).await
319 }
320
321 pub async fn ack(&self, message_id: &str) -> Result<(), MqError> {
322 self.queue.ack(message_id).await
323 }
324
325 pub async fn subscribe(&self, topic: &str) -> Result<(), MqError> {
326 self.queue.subscribe(topic).await
327 }
328}
329
330#[cfg(test)]
331mod tests {
332 use super::*;
333
334 #[tokio::test]
335 async fn test_in_memory_queue_basic() {
336 let queue = InMemoryQueue::new();
337 queue.publish("topic1", b"hello").await.unwrap();
338 let msg = queue
339 .consume("topic1")
340 .await
341 .unwrap()
342 .expect("msg should exist");
343 assert_eq!(msg.payload, b"hello");
344 queue.ack(&msg.id).await.unwrap();
345 }
346
347 #[tokio::test]
351 async fn test_l2_next_id_overflow_protection() {
352 let queue = InMemoryQueue::new();
353 {
355 let mut inner = queue.inner.write().await;
356 inner.next_id = u64::MAX;
357 }
358 let result = queue.publish("topic1", b"msg").await;
360 assert!(result.is_err());
361 match result {
362 Err(MqError::Publish(msg)) => {
363 assert!(
364 msg.contains("overflow"),
365 "expected overflow error, got: {}",
366 msg
367 );
368 }
369 _ => panic!("Expected MqError::Publish with overflow message"),
370 }
371 }
372
373 #[tokio::test]
375 async fn test_l2_next_id_near_max() {
376 let queue = InMemoryQueue::new();
377 {
378 let mut inner = queue.inner.write().await;
379 inner.next_id = u64::MAX - 1;
380 }
381 let result1 = queue.publish("topic1", b"msg1").await;
383 assert!(result1.is_ok());
384 let result2 = queue.publish("topic1", b"msg2").await;
386 assert!(result2.is_err());
387 }
388}