sz_rust_core/plugin/
event_bus.rs1use async_trait::async_trait;
7use serde::{Deserialize, Serialize};
8use std::sync::Arc;
9
10use super::schema::SysEvent;
11
12pub type EventId = i64;
14
15pub type SubscriptionId = u64;
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct PluginEvent {
21 pub id: EventId,
23 pub tenant_id: i64,
25 pub event_type: String,
27 pub source_plugin: String,
29 pub payload: serde_json::Value,
31}
32
33impl From<SysEvent> for PluginEvent {
34 fn from(e: SysEvent) -> Self {
35 Self {
36 id: e.id,
37 tenant_id: e.tenant_id,
38 event_type: e.event_type,
39 source_plugin: e.source_plugin,
40 payload: e.payload,
41 }
42 }
43}
44
45#[async_trait]
47pub trait EventHandler: Send + Sync + 'static {
48 async fn handle(&self, event: &PluginEvent) -> Result<(), String>;
50}
51
52#[async_trait]
54pub trait EventBus: Send + Sync + 'static {
55 async fn publish(&self, event: &PluginEvent) -> Result<EventId, String>;
57
58 async fn subscribe(
60 &self,
61 event_type: &str,
62 handler: Arc<dyn EventHandler>,
63 ) -> Result<SubscriptionId, String>;
64
65 async fn unsubscribe(&self, sub_id: SubscriptionId) -> Result<(), String>;
67
68 async fn replay_pending(&self) -> Result<usize, String>;
70}
71
72pub type SubscriptionEntry = (SubscriptionId, Arc<dyn EventHandler>);
74
75pub type SubscriptionMap = std::collections::HashMap<String, Vec<SubscriptionEntry>>;
77
78pub struct InMemoryEventBus {
80 events: parking_lot::RwLock<Vec<PluginEvent>>,
82 next_id: parking_lot::Mutex<EventId>,
84 subscribers: parking_lot::RwLock<SubscriptionMap>,
86 next_sub_id: parking_lot::Mutex<SubscriptionId>,
88}
89
90impl InMemoryEventBus {
91 pub fn new() -> Self {
93 Self {
94 events: parking_lot::RwLock::new(Vec::new()),
95 next_id: parking_lot::Mutex::new(1),
96 subscribers: parking_lot::RwLock::new(std::collections::HashMap::new()),
97 next_sub_id: parking_lot::Mutex::new(1),
98 }
99 }
100}
101
102impl Default for InMemoryEventBus {
103 fn default() -> Self {
104 Self::new()
105 }
106}
107
108#[async_trait]
109impl EventBus for InMemoryEventBus {
110 async fn publish(&self, event: &PluginEvent) -> Result<EventId, String> {
111 let id = {
112 let mut next = self.next_id.lock();
113 let id = *next;
114 *next += 1;
115 id
116 };
117 let mut event = event.clone();
118 event.id = id;
119 let event_type = event.event_type.clone();
120 self.events.write().push(event.clone());
121 let handlers: Vec<Arc<dyn EventHandler>> = {
122 let subs = self.subscribers.read();
123 subs.get(&event_type)
124 .map(|v| v.iter().map(|(_, h)| h.clone()).collect())
125 .unwrap_or_default()
126 };
127 for handler in handlers {
128 let _ = handler.handle(&event).await;
129 }
130 Ok(id)
131 }
132
133 async fn subscribe(
134 &self,
135 event_type: &str,
136 handler: Arc<dyn EventHandler>,
137 ) -> Result<SubscriptionId, String> {
138 let sub_id = {
139 let mut next = self.next_sub_id.lock();
140 let id = *next;
141 *next += 1;
142 id
143 };
144 let mut subs = self.subscribers.write();
145 subs.entry(event_type.to_string())
146 .or_default()
147 .push((sub_id, handler));
148 Ok(sub_id)
149 }
150
151 async fn unsubscribe(&self, sub_id: SubscriptionId) -> Result<(), String> {
152 let mut subs = self.subscribers.write();
153 for handlers in subs.values_mut() {
154 handlers.retain(|(id, _)| *id != sub_id);
155 }
156 Ok(())
157 }
158
159 async fn replay_pending(&self) -> Result<usize, String> {
160 Ok(0)
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 struct CountHandler {
169 count: parking_lot::Mutex<usize>,
170 }
171
172 #[async_trait]
173 impl EventHandler for CountHandler {
174 async fn handle(&self, _event: &PluginEvent) -> Result<(), String> {
175 *self.count.lock() += 1;
176 Ok(())
177 }
178 }
179
180 #[tokio::test]
181 async fn test_publish_and_subscribe() {
182 let bus = InMemoryEventBus::new();
183 let handler = Arc::new(CountHandler {
184 count: parking_lot::Mutex::new(0),
185 });
186 let _ = bus.subscribe("test.event", handler.clone()).await;
187 let event = PluginEvent {
188 id: 0,
189 tenant_id: 1,
190 event_type: "test.event".to_string(),
191 source_plugin: "test".to_string(),
192 payload: serde_json::json!({}),
193 };
194 let id = bus.publish(&event).await.expect("发布失败");
195 assert!(id > 0);
196 assert_eq!(*handler.count.lock(), 1);
197 }
198}