1use std::collections::{HashSet, VecDeque};
4use std::sync::Arc;
5use std::time::Duration;
6
7use async_trait::async_trait;
8use rskit_errors::{AppError, AppResult, ErrorCode};
9use tokio::sync::{Mutex, broadcast};
10
11use crate::config::BrokerConfig;
12use crate::event::Event;
13use crate::message::Message;
14use crate::registry::{MessagingFactory, MessagingRegistry};
15use crate::traits::{EventConsumer, EventProducer, MessageConsumer, MessageProducer};
16
17const ADAPTER_NAME: &str = "memory";
18
19#[derive(Debug, Clone)]
27pub struct InMemoryBroker<T: Clone + Send + Sync + 'static> {
28 tx: broadcast::Sender<Message<T>>,
29 history: Arc<Mutex<VecDeque<Message<T>>>>,
30 history_limit: Option<usize>,
31 topics: Arc<Mutex<HashSet<String>>>,
32 notify: Arc<tokio::sync::Notify>,
35}
36
37impl<T: Clone + Send + Sync + 'static> InMemoryBroker<T> {
38 pub fn new(capacity: usize) -> Self {
40 let limit = capacity.max(1);
41 let (tx, _) = broadcast::channel(limit);
42 Self {
43 tx,
44 history: Arc::new(Mutex::new(VecDeque::with_capacity(limit))),
45 history_limit: Some(limit),
46 topics: Arc::new(Mutex::new(HashSet::new())),
47 notify: Arc::new(tokio::sync::Notify::new()),
48 }
49 }
50
51 pub fn producer(&self) -> InMemoryProducer<T> {
53 InMemoryProducer {
54 tx: self.tx.clone(),
55 history: self.history.clone(),
56 history_limit: self.history_limit,
57 topics: self.topics.clone(),
58 notify: self.notify.clone(),
59 }
60 }
61
62 #[must_use]
67 pub fn with_history_limit(capacity: usize, history_limit: usize) -> Self {
68 let capacity = capacity.max(1);
69 let limit = history_limit.max(1);
70 let (tx, _) = broadcast::channel(capacity);
71 Self {
72 tx,
73 history: Arc::new(Mutex::new(VecDeque::with_capacity(limit))),
74 history_limit: Some(limit),
75 topics: Arc::new(Mutex::new(HashSet::new())),
76 notify: Arc::new(tokio::sync::Notify::new()),
77 }
78 }
79
80 pub fn consumer(&self) -> InMemoryConsumer<T> {
82 InMemoryConsumer {
83 rx: Arc::new(Mutex::new(self.tx.subscribe())),
84 topics: Arc::new(Mutex::new(HashSet::new())),
85 }
86 }
87
88 pub async fn messages(&self, topic: &str) -> Vec<Message<T>> {
90 self.history
91 .lock()
92 .await
93 .iter()
94 .filter(|m| m.topic == topic)
95 .cloned()
96 .collect()
97 }
98
99 pub async fn all_messages(&self) -> Vec<Message<T>> {
101 self.history.lock().await.iter().cloned().collect()
102 }
103
104 pub async fn message_count(&self, topic: &str) -> usize {
106 self.history
107 .lock()
108 .await
109 .iter()
110 .filter(|m| m.topic == topic)
111 .count()
112 }
113
114 pub async fn reset(&self) {
116 self.history.lock().await.clear();
117 }
118
119 pub async fn create_topic(&self, topic: &str) {
121 self.topics.lock().await.insert(topic.to_string());
122 }
123
124 pub async fn topic_names(&self) -> Vec<String> {
126 let mut set: HashSet<String> = self.topics.lock().await.clone();
127 {
128 let hist = self.history.lock().await;
129 for m in hist.iter() {
130 set.insert(m.topic.clone());
131 }
132 }
133 let mut out: Vec<String> = set.into_iter().collect();
134 out.sort();
135 out
136 }
137}
138
139impl<T: Clone + Send + Sync + 'static> Default for InMemoryBroker<T> {
140 fn default() -> Self {
141 Self::new(256)
142 }
143}
144
145pub fn register<T: Clone + Send + Sync + 'static>(
147 registry: &mut MessagingRegistry<T>,
148 broker: InMemoryBroker<T>,
149) -> AppResult<()> {
150 registry.register_backend(ADAPTER_NAME, Arc::new(MemoryFactory { broker }))
151}
152
153struct MemoryFactory<T: Clone + Send + Sync + 'static> {
154 broker: InMemoryBroker<T>,
155}
156
157impl<T: Clone + Send + Sync + 'static> MessagingFactory<T> for MemoryFactory<T> {
158 fn create_producer(&self, _config: &BrokerConfig) -> AppResult<Arc<dyn MessageProducer<T>>> {
159 Ok(Arc::new(self.broker.producer()))
160 }
161
162 fn create_consumer(&self, _config: &BrokerConfig) -> AppResult<Arc<dyn MessageConsumer<T>>> {
163 Ok(Arc::new(self.broker.consumer()))
164 }
165}
166
167#[derive(Debug, Clone)]
169pub struct InMemoryProducer<T: Clone + Send + Sync + 'static> {
170 tx: broadcast::Sender<Message<T>>,
171 history: Arc<Mutex<VecDeque<Message<T>>>>,
172 history_limit: Option<usize>,
173 topics: Arc<Mutex<HashSet<String>>>,
174 notify: Arc<tokio::sync::Notify>,
175}
176
177#[async_trait]
178impl<T: Clone + Send + Sync + 'static> MessageProducer<T> for InMemoryProducer<T> {
179 async fn send(&self, msg: Message<T>) -> AppResult<()> {
180 {
182 let mut hist = self.history.lock().await;
183 if let Some(limit) = self.history_limit
184 && hist.len() == limit
185 {
186 hist.pop_front();
187 }
188 hist.push_back(msg.clone());
189 }
190 {
191 let mut set = self.topics.lock().await;
192 set.insert(msg.topic.clone());
193 }
194
195 self.tx.send(msg).map_err(|_| {
196 AppError::new(ErrorCode::ExternalService, "no active consumers on channel")
197 })?;
198
199 self.notify.notify_waiters();
200 Ok(())
201 }
202
203 async fn send_batch(&self, msgs: Vec<Message<T>>) -> AppResult<()> {
204 for msg in msgs {
205 self.send(msg).await?;
206 }
207 Ok(())
208 }
209
210 async fn flush(&self, _timeout: Duration) -> AppResult<()> {
211 Ok(())
213 }
214}
215
216#[derive(Debug)]
218pub struct InMemoryConsumer<T: Clone + Send + Sync + 'static> {
219 rx: Arc<Mutex<broadcast::Receiver<Message<T>>>>,
220 topics: Arc<Mutex<HashSet<String>>>,
221}
222
223impl<T: Clone + Send + Sync + 'static> Clone for InMemoryConsumer<T> {
225 fn clone(&self) -> Self {
226 Self {
227 rx: self.rx.clone(),
228 topics: self.topics.clone(),
229 }
230 }
231}
232
233#[async_trait]
234impl<T: Clone + Send + Sync + 'static> MessageConsumer<T> for InMemoryConsumer<T> {
235 async fn subscribe(&self, topics: &[&str]) -> AppResult<()> {
236 {
237 let mut set = self.topics.lock().await;
238 for t in topics {
239 set.insert((*t).to_string());
240 }
241 }
242 Ok(())
243 }
244
245 async fn recv(&self) -> AppResult<Message<T>> {
246 loop {
247 let msg = {
248 let mut rx = self.rx.lock().await;
249 rx.recv().await.map_err(|e| {
250 AppError::new(ErrorCode::ExternalService, format!("receive failed: {e}"))
251 })?
252 };
253
254 let topics = self.topics.lock().await;
255 if topics.is_empty() || topics.contains(&msg.topic) {
257 return Ok(msg);
258 }
259 }
261 }
262}
263
264#[async_trait]
265impl EventProducer for InMemoryProducer<serde_json::Value> {
266 async fn publish(&self, topic: &str, event: Event) -> AppResult<()> {
267 let value = serde_json::to_value(&event).map_err(|e| {
268 AppError::new(
269 ErrorCode::Internal,
270 format!("Failed to serialize event: {e}"),
271 )
272 })?;
273 self.send(Message::new(topic, value)).await
274 }
275
276 async fn publish_batch(&self, topic: &str, events: Vec<Event>) -> AppResult<()> {
277 for event in events {
278 self.publish(topic, event).await?;
279 }
280 Ok(())
281 }
282}
283
284#[async_trait]
285impl EventConsumer for InMemoryConsumer<serde_json::Value> {
286 async fn subscribe(&self, topics: &[&str]) -> AppResult<()> {
287 MessageConsumer::subscribe(self, topics).await
288 }
289
290 async fn recv_event(&self) -> AppResult<Event> {
291 let msg = self.recv().await?;
292 serde_json::from_value(msg.payload).map_err(|e| {
293 AppError::new(
294 ErrorCode::Internal,
295 format!("Failed to deserialize event: {e}"),
296 )
297 })
298 }
299}
300
301pub async fn assert_published<T: Clone + Send + Sync + 'static>(
307 broker: &InMemoryBroker<T>,
308 topic: &str,
309 predicate: impl Fn(&Message<T>) -> bool,
310) {
311 let msgs = broker.messages(topic).await;
312 assert!(
313 msgs.iter().any(&predicate),
314 "assert_published: no message on topic {topic:?} matched the predicate ({} checked)",
315 msgs.len(),
316 );
317}
318
319pub async fn assert_published_n<T: Clone + Send + Sync + 'static>(
325 broker: &InMemoryBroker<T>,
326 topic: &str,
327 n: usize,
328) {
329 let got = broker.message_count(topic).await;
330 assert_eq!(
331 got, n,
332 "assert_published_n: topic {topic:?} has {got} messages, want {n}",
333 );
334}
335
336pub async fn wait_for_message<T: Clone + Send + Sync + 'static>(
344 broker: &InMemoryBroker<T>,
345 topic: &str,
346 timeout: Duration,
347) -> Message<T> {
348 let deadline = tokio::time::Instant::now() + timeout;
349
350 loop {
351 let msgs = broker.messages(topic).await;
352 if let Some(m) = msgs.into_iter().next() {
353 return m;
354 }
355 tokio::select! {
356 () = broker.notify.notified() => { }
357 () = tokio::time::sleep_until(deadline) => {
358 panic!("wait_for_message: timed out after {timeout:?} waiting for message on topic {topic:?}");
359 }
360 }
361 }
362}
363
364pub async fn assert_no_messages<T: Clone + Send + Sync + 'static>(
370 broker: &InMemoryBroker<T>,
371 topic: &str,
372) {
373 let n = broker.message_count(topic).await;
374 assert_eq!(
375 n, 0,
376 "assert_no_messages: topic {topic:?} has {n} messages, want 0",
377 );
378}
379
380#[cfg(test)]
381mod tests {
382 use super::*;
383
384 #[tokio::test]
385 async fn send_and_receive() {
386 let broker: InMemoryBroker<String> = InMemoryBroker::new(16);
387 let producer = broker.producer();
388 let consumer = broker.consumer();
389
390 consumer.subscribe(&["test-topic"]).await.unwrap();
391
392 let msg = Message::new("test-topic", "hello".to_string());
393 producer.send(msg).await.unwrap();
394
395 let received = consumer.recv().await.unwrap();
396 assert_eq!(received.topic, "test-topic");
397 assert_eq!(received.payload, "hello");
398 }
399
400 #[tokio::test]
401 async fn register_memory_adapter_explicitly() {
402 let broker: InMemoryBroker<String> = InMemoryBroker::new(16);
403 let mut registry = MessagingRegistry::new();
404
405 register(&mut registry, broker).unwrap();
406
407 assert_eq!(registry.adapters(), vec!["memory"]);
408 let config = BrokerConfig::default();
409 let producer = registry.producer(&config).unwrap();
410 let consumer = registry.consumer(&config).unwrap();
411 consumer.subscribe(&["events"]).await.unwrap();
412 producer
413 .send(Message::new("events", "registered".to_string()))
414 .await
415 .unwrap();
416 let received = consumer.recv().await.unwrap();
417 assert_eq!(received.payload, "registered");
418 }
419
420 #[tokio::test]
421 async fn send_batch_and_receive() {
422 let broker: InMemoryBroker<i32> = InMemoryBroker::new(16);
423 let producer = broker.producer();
424 let consumer = broker.consumer();
425
426 consumer.subscribe(&["numbers"]).await.unwrap();
427
428 let msgs = vec![
429 Message::new("numbers", 1),
430 Message::new("numbers", 2),
431 Message::new("numbers", 3),
432 ];
433 producer.send_batch(msgs).await.unwrap();
434
435 let a = consumer.recv().await.unwrap();
436 let b = consumer.recv().await.unwrap();
437 let c = consumer.recv().await.unwrap();
438 assert_eq!(a.payload, 1);
439 assert_eq!(b.payload, 2);
440 assert_eq!(c.payload, 3);
441 }
442
443 #[tokio::test]
444 async fn topic_filtering() {
445 let broker: InMemoryBroker<String> = InMemoryBroker::new(16);
446 let producer = broker.producer();
447 let consumer = broker.consumer();
448
449 consumer.subscribe(&["wanted"]).await.unwrap();
450
451 producer
452 .send(Message::new("ignored", "nope".to_string()))
453 .await
454 .unwrap();
455 producer
456 .send(Message::new("wanted", "yes".to_string()))
457 .await
458 .unwrap();
459
460 let received = consumer.recv().await.unwrap();
461 assert_eq!(received.topic, "wanted");
462 assert_eq!(received.payload, "yes");
463 }
464
465 #[tokio::test]
466 async fn flush_is_noop() {
467 let broker: InMemoryBroker<()> = InMemoryBroker::new(4);
468 let producer = broker.producer();
469 producer.flush(Duration::from_secs(1)).await.unwrap();
470 }
471
472 #[tokio::test]
473 async fn event_publish_and_receive() {
474 let broker: InMemoryBroker<serde_json::Value> = InMemoryBroker::new(16);
475 let producer = broker.producer();
476 let consumer = broker.consumer();
477
478 EventConsumer::subscribe(&consumer, &["events"])
479 .await
480 .unwrap();
481
482 let event = Event::new("user.created", "auth-service")
483 .with_subject("user-42")
484 .with_data(serde_json::json!({"name": "Alice"}))
485 .unwrap();
486 let original_id = event.id.clone();
487
488 producer.publish("events", event).await.unwrap();
489
490 let received = consumer.recv_event().await.unwrap();
491 assert_eq!(received.id, original_id);
492 assert_eq!(received.event_type, "user.created");
493 assert_eq!(received.source, "auth-service");
494 assert_eq!(received.subject, "user-42");
495 assert_eq!(received.data, serde_json::json!({"name": "Alice"}));
496 }
497
498 #[tokio::test]
499 async fn event_publish_batch_and_receive() {
500 let broker: InMemoryBroker<serde_json::Value> = InMemoryBroker::new(16);
501 let producer = broker.producer();
502 let consumer = broker.consumer();
503
504 EventConsumer::subscribe(&consumer, &["batch"])
505 .await
506 .unwrap();
507
508 let events = vec![
509 Event::new("a", "src"),
510 Event::new("b", "src"),
511 Event::new("c", "src"),
512 ];
513 producer.publish_batch("batch", events).await.unwrap();
514
515 let a = consumer.recv_event().await.unwrap();
516 let b = consumer.recv_event().await.unwrap();
517 let c = consumer.recv_event().await.unwrap();
518 assert_eq!(a.event_type, "a");
519 assert_eq!(b.event_type, "b");
520 assert_eq!(c.event_type, "c");
521 }
522
523 #[tokio::test]
526 async fn messages_returns_topic_history() {
527 let broker: InMemoryBroker<String> = InMemoryBroker::new(16);
528 let producer = broker.producer();
529 let _consumer = broker.consumer();
531
532 producer
533 .send(Message::new("t1", "a".to_string()))
534 .await
535 .unwrap();
536 producer
537 .send(Message::new("t1", "b".to_string()))
538 .await
539 .unwrap();
540 producer
541 .send(Message::new("t2", "c".to_string()))
542 .await
543 .unwrap();
544
545 let t1 = broker.messages("t1").await;
546 assert_eq!(t1.len(), 2);
547 assert_eq!(t1[0].payload, "a");
548 assert_eq!(t1[1].payload, "b");
549
550 let all = broker.all_messages().await;
551 assert_eq!(all.len(), 3);
552 }
553
554 #[tokio::test]
555 async fn in_memory_history_is_bounded() {
556 let broker = InMemoryBroker::with_history_limit(8, 2);
557 let producer = broker.producer();
558 let _consumer = broker.consumer();
559
560 producer.send(Message::new("events", 1_u32)).await.unwrap();
561 producer.send(Message::new("events", 2_u32)).await.unwrap();
562 producer.send(Message::new("events", 3_u32)).await.unwrap();
563
564 let messages = broker.messages("events").await;
565 assert_eq!(messages.len(), 2);
566 assert_eq!(messages[0].payload, 2);
567 assert_eq!(messages[1].payload, 3);
568 }
569
570 #[tokio::test]
571 async fn message_count_and_reset() {
572 let broker: InMemoryBroker<i32> = InMemoryBroker::new(16);
573 let producer = broker.producer();
574 let _consumer = broker.consumer();
575
576 assert_eq!(broker.message_count("t").await, 0);
577 producer.send(Message::new("t", 1)).await.unwrap();
578 assert_eq!(broker.message_count("t").await, 1);
579
580 broker.reset().await;
581 assert_eq!(broker.message_count("t").await, 0);
582 }
583
584 #[tokio::test]
585 async fn create_topic_and_topic_names() {
586 let broker: InMemoryBroker<String> = InMemoryBroker::new(16);
587 let _consumer = broker.consumer();
588
589 broker.create_topic("z-topic").await;
590 broker.create_topic("a-topic").await;
591
592 producer_send_helper(&broker, "m-topic").await;
593
594 let names = broker.topic_names().await;
595 assert_eq!(names, vec!["a-topic", "m-topic", "z-topic"]);
596 }
597
598 async fn producer_send_helper(broker: &InMemoryBroker<String>, topic: &str) {
600 let producer = broker.producer();
601 producer
602 .send(Message::new(topic, "x".to_string()))
603 .await
604 .unwrap();
605 }
606
607 #[tokio::test]
610 async fn test_assert_published() {
611 let broker: InMemoryBroker<String> = InMemoryBroker::new(16);
612 let producer = broker.producer();
613 let _consumer = broker.consumer();
614
615 producer
616 .send(Message::new("t1", "hello".to_string()))
617 .await
618 .unwrap();
619 producer
620 .send(Message::new("t1", "world".to_string()))
621 .await
622 .unwrap();
623
624 assert_published(&broker, "t1", |m| m.payload == "world").await;
625 }
626
627 #[tokio::test]
628 async fn test_assert_published_n() {
629 let broker: InMemoryBroker<String> = InMemoryBroker::new(16);
630 let producer = broker.producer();
631 let _consumer = broker.consumer();
632
633 producer
634 .send(Message::new("t1", "a".to_string()))
635 .await
636 .unwrap();
637 producer
638 .send(Message::new("t1", "b".to_string()))
639 .await
640 .unwrap();
641
642 assert_published_n(&broker, "t1", 2).await;
643 }
644
645 #[tokio::test]
646 async fn test_assert_no_messages() {
647 let broker: InMemoryBroker<String> = InMemoryBroker::new(16);
648 assert_no_messages(&broker, "empty-topic").await;
649 }
650
651 #[tokio::test]
652 async fn test_wait_for_message() {
653 let broker: InMemoryBroker<String> = InMemoryBroker::new(16);
654 let _consumer = broker.consumer();
655
656 let broker_clone = broker.clone();
657 tokio::spawn(async move {
658 tokio::time::sleep(Duration::from_millis(20)).await;
659 let producer = broker_clone.producer();
660 producer
661 .send(Message::new("t1", "delayed".to_string()))
662 .await
663 .unwrap();
664 });
665
666 let msg = wait_for_message(&broker, "t1", Duration::from_secs(2)).await;
667 assert_eq!(msg.payload, "delayed");
668 }
669 #[tokio::test]
670 async fn default_history_is_bounded_by_capacity() {
671 let broker: InMemoryBroker<usize> = InMemoryBroker::new(8);
672 let producer = broker.producer();
673 let _consumer = broker.consumer();
674
675 for value in 0..1030 {
676 producer.send(Message::new("history", value)).await.unwrap();
677 }
678
679 let messages = broker.messages("history").await;
680 assert_eq!(messages.len(), 8);
681 assert_eq!(messages.first().map(|msg| msg.payload), Some(1022));
682 }
683
684 #[tokio::test]
685 async fn bounded_history_limit_is_opt_in() {
686 let broker: InMemoryBroker<usize> = InMemoryBroker::with_history_limit(8, 2);
687 let producer = broker.producer();
688 let _consumer = broker.consumer();
689
690 for value in 0..4 {
691 producer.send(Message::new("history", value)).await.unwrap();
692 }
693
694 let payloads = broker
695 .messages("history")
696 .await
697 .into_iter()
698 .map(|msg| msg.payload)
699 .collect::<Vec<_>>();
700 assert_eq!(payloads, vec![2, 3]);
701 }
702
703 #[tokio::test]
704 async fn zero_capacity_is_clamped() {
705 let broker: InMemoryBroker<usize> = InMemoryBroker::new(0);
706 let producer = broker.producer();
707 let _consumer = broker.consumer();
708
709 producer.send(Message::new("history", 1)).await.unwrap();
710
711 let messages = broker.messages("history").await;
712 assert_eq!(messages.len(), 1);
713 }
714}