1use std::{
2 collections::HashMap,
3 hash::Hash,
4 sync::{Arc, Mutex},
5};
6
7use tokio::sync::broadcast;
8
9pub struct Broker<Topic, Message> {
14 capacity: usize,
15 topics: Arc<Mutex<HashMap<Topic, broadcast::Sender<Message>>>>,
16}
17
18impl<Topic, Message> Clone for Broker<Topic, Message> {
19 fn clone(&self) -> Self {
20 Self {
21 capacity: self.capacity,
22 topics: Arc::clone(&self.topics),
23 }
24 }
25}
26
27impl<Topic, Message> Broker<Topic, Message>
28where
29 Topic: Clone + Eq + Hash,
30 Message: Clone,
31{
32 pub fn new(capacity: usize) -> Self {
33 assert!(capacity > 0, "broker capacity must be greater than zero");
34 Self {
35 capacity,
36 topics: Arc::new(Mutex::new(HashMap::new())),
37 }
38 }
39
40 pub fn subscribe(&self, topic: Topic) -> Subscription<Message> {
41 let mut topics = self.topics.lock().expect("broker lock poisoned");
42 let sender = topics.entry(topic).or_insert_with(|| {
43 let (sender, _) = broadcast::channel(self.capacity);
44 sender
45 });
46 Subscription {
47 receiver: sender.subscribe(),
48 }
49 }
50
51 pub fn publish(&self, topic: Topic, message: Message) -> usize {
53 let mut topics = self.topics.lock().expect("broker lock poisoned");
54 let sender = topics.entry(topic).or_insert_with(|| {
55 let (sender, _) = broadcast::channel(self.capacity);
56 sender
57 });
58 sender.send(message).unwrap_or(0)
59 }
60
61 pub fn subscriber_count(&self, topic: &Topic) -> usize {
62 self.topics
63 .lock()
64 .expect("broker lock poisoned")
65 .get(topic)
66 .map_or(0, broadcast::Sender::receiver_count)
67 }
68}
69
70pub struct Subscription<Message> {
72 receiver: broadcast::Receiver<Message>,
73}
74
75impl<Message> Subscription<Message>
76where
77 Message: Clone,
78{
79 pub async fn recv(&mut self) -> Result<Message, broadcast::error::RecvError> {
80 self.receiver.recv().await
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[tokio::test]
89 async fn fans_messages_out_to_topic_subscribers() {
90 let broker = Broker::new(8);
91 let mut first = broker.subscribe("orders");
92 let mut second = broker.subscribe("orders");
93 let mut unrelated = broker.subscribe("users");
94
95 assert_eq!(broker.publish("orders", 42), 2);
96 assert_eq!(first.recv().await.unwrap(), 42);
97 assert_eq!(second.recv().await.unwrap(), 42);
98 assert!(unrelated.receiver.try_recv().is_err());
99 }
100}