1use crate::Result;
4use async_trait::async_trait;
5use dashmap::DashMap;
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::sync::Arc;
9use tokio::sync::RwLock;
10use uuid::Uuid;
11
12pub trait Event: Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static {
14 fn topic(&self) -> String;
16}
17
18#[async_trait]
20pub trait Subscriber: Send + Sync + 'static {
21 fn topic_pattern(&self) -> &str;
23
24 async fn handle(&mut self, topic: &str, payload: Vec<u8>) -> Result<()>;
26}
27
28pub trait SyncSubscriber: Send + Sync + 'static {
30 fn topic_pattern(&self) -> &str;
32
33 fn handle_sync(&mut self, topic: &str, payload: Vec<u8>) -> Result<()>;
35}
36
37pub struct Subscription {
39 pub id: Uuid,
40 pub topic_pattern: String,
41 registry: Arc<SubscriptionRegistry>,
42}
43
44impl Subscription {
45 pub async fn unsubscribe(self) -> Result<()> {
47 self.registry.unsubscribe(&self.id).await
48 }
49}
50
51impl Drop for Subscription {
52 fn drop(&mut self) {
53 let id = self.id;
55 let registry = self.registry.clone();
56 tokio::spawn(async move {
57 let _ = registry.unsubscribe(&id).await;
58 });
59 }
60}
61
62pub struct SubscriptionRegistry {
64 subscribers: Arc<DashMap<Uuid, Box<dyn Subscriber>>>,
66
67 topic_subscriptions: Arc<RwLock<HashMap<String, Vec<Uuid>>>>,
69}
70
71impl SubscriptionRegistry {
72 pub fn new() -> Self {
73 Self {
74 subscribers: Arc::new(DashMap::new()),
75 topic_subscriptions: Arc::new(RwLock::new(HashMap::new())),
76 }
77 }
78
79 pub async fn subscribe<S: Subscriber>(&self, subscriber: S) -> Result<Subscription> {
81 let id = Uuid::new_v4();
82 let topic_pattern = subscriber.topic_pattern().to_string();
83
84 self.subscribers.insert(id, Box::new(subscriber));
86
87 let mut topics = self.topic_subscriptions.write().await;
89 topics
90 .entry(topic_pattern.clone())
91 .or_insert_with(Vec::new)
92 .push(id);
93
94 Ok(Subscription {
95 id,
96 topic_pattern,
97 registry: Arc::new(self.clone()),
98 })
99 }
100
101 pub async fn unsubscribe(&self, id: &Uuid) -> Result<()> {
103 if let Some((_, subscriber)) = self.subscribers.remove(id) {
105 let topic_pattern = subscriber.topic_pattern();
106
107 let mut topics = self.topic_subscriptions.write().await;
109 if let Some(subs) = topics.get_mut(topic_pattern) {
110 subs.retain(|sub_id| sub_id != id);
111 if subs.is_empty() {
112 topics.remove(topic_pattern);
113 }
114 }
115 }
116
117 Ok(())
118 }
119
120 pub async fn publish(&self, topic: &str, payload: Vec<u8>) -> Result<()> {
122 let topics = self.topic_subscriptions.read().await;
123 let mut matching_ids = Vec::new();
124
125 for (pattern, ids) in topics.iter() {
127 if topic_matches(topic, pattern) {
128 matching_ids.extend(ids.iter().copied());
129 }
130 }
131 drop(topics);
132
133 for id in matching_ids {
135 if let Some(mut subscriber) = self.subscribers.get_mut(&id) {
136 let _ = subscriber.handle(topic, payload.clone()).await;
138 }
139 }
140
141 Ok(())
142 }
143}
144
145impl Clone for SubscriptionRegistry {
146 fn clone(&self) -> Self {
147 Self {
148 subscribers: self.subscribers.clone(),
149 topic_subscriptions: self.topic_subscriptions.clone(),
150 }
151 }
152}
153
154impl Default for SubscriptionRegistry {
155 fn default() -> Self {
156 Self::new()
157 }
158}
159
160fn topic_matches(topic: &str, pattern: &str) -> bool {
163 if topic == pattern {
165 return true;
166 }
167
168 let topic_parts: Vec<&str> = topic.split('/').collect();
169 let pattern_parts: Vec<&str> = pattern.split('/').collect();
170
171 let mut t_idx = 0;
172 let mut p_idx = 0;
173
174 while p_idx < pattern_parts.len() && t_idx < topic_parts.len() {
175 match pattern_parts[p_idx] {
176 "#" => return true, "+" => {
178 t_idx += 1;
180 p_idx += 1;
181 }
182 part => {
183 if part != topic_parts[t_idx] {
184 return false;
185 }
186 t_idx += 1;
187 p_idx += 1;
188 }
189 }
190 }
191
192 t_idx == topic_parts.len() && p_idx == pattern_parts.len()
194}
195
196pub struct SyncSubscriberAdapter<S: SyncSubscriber> {
198 inner: S,
199}
200
201impl<S: SyncSubscriber> SyncSubscriberAdapter<S> {
202 pub fn new(subscriber: S) -> Self {
203 Self { inner: subscriber }
204 }
205}
206
207#[async_trait]
208impl<S: SyncSubscriber> Subscriber for SyncSubscriberAdapter<S> {
209 fn topic_pattern(&self) -> &str {
210 self.inner.topic_pattern()
211 }
212
213 async fn handle(&mut self, _topic: &str, _payload: Vec<u8>) -> Result<()> {
214 Ok(())
217 }
218}