use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use super::schema::SysEvent;
pub type EventId = i64;
pub type SubscriptionId = u64;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PluginEvent {
pub id: EventId,
pub tenant_id: i64,
pub event_type: String,
pub source_plugin: String,
pub payload: serde_json::Value,
}
impl From<SysEvent> for PluginEvent {
fn from(e: SysEvent) -> Self {
Self {
id: e.id,
tenant_id: e.tenant_id,
event_type: e.event_type,
source_plugin: e.source_plugin,
payload: e.payload,
}
}
}
#[async_trait]
pub trait EventHandler: Send + Sync + 'static {
async fn handle(&self, event: &PluginEvent) -> Result<(), String>;
}
#[async_trait]
pub trait EventBus: Send + Sync + 'static {
async fn publish(&self, event: &PluginEvent) -> Result<EventId, String>;
async fn subscribe(
&self,
event_type: &str,
handler: Arc<dyn EventHandler>,
) -> Result<SubscriptionId, String>;
async fn unsubscribe(&self, sub_id: SubscriptionId) -> Result<(), String>;
async fn replay_pending(&self) -> Result<usize, String>;
}
pub type SubscriptionEntry = (SubscriptionId, Arc<dyn EventHandler>);
pub type SubscriptionMap = std::collections::HashMap<String, Vec<SubscriptionEntry>>;
pub struct InMemoryEventBus {
events: parking_lot::RwLock<Vec<PluginEvent>>,
next_id: parking_lot::Mutex<EventId>,
subscribers: parking_lot::RwLock<SubscriptionMap>,
next_sub_id: parking_lot::Mutex<SubscriptionId>,
}
impl InMemoryEventBus {
pub fn new() -> Self {
Self {
events: parking_lot::RwLock::new(Vec::new()),
next_id: parking_lot::Mutex::new(1),
subscribers: parking_lot::RwLock::new(std::collections::HashMap::new()),
next_sub_id: parking_lot::Mutex::new(1),
}
}
}
impl Default for InMemoryEventBus {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl EventBus for InMemoryEventBus {
async fn publish(&self, event: &PluginEvent) -> Result<EventId, String> {
let id = {
let mut next = self.next_id.lock();
let id = *next;
*next += 1;
id
};
let mut event = event.clone();
event.id = id;
let event_type = event.event_type.clone();
self.events.write().push(event.clone());
let handlers: Vec<Arc<dyn EventHandler>> = {
let subs = self.subscribers.read();
subs.get(&event_type)
.map(|v| v.iter().map(|(_, h)| h.clone()).collect())
.unwrap_or_default()
};
for handler in handlers {
let _ = handler.handle(&event).await;
}
Ok(id)
}
async fn subscribe(
&self,
event_type: &str,
handler: Arc<dyn EventHandler>,
) -> Result<SubscriptionId, String> {
let sub_id = {
let mut next = self.next_sub_id.lock();
let id = *next;
*next += 1;
id
};
let mut subs = self.subscribers.write();
subs.entry(event_type.to_string())
.or_default()
.push((sub_id, handler));
Ok(sub_id)
}
async fn unsubscribe(&self, sub_id: SubscriptionId) -> Result<(), String> {
let mut subs = self.subscribers.write();
for handlers in subs.values_mut() {
handlers.retain(|(id, _)| *id != sub_id);
}
Ok(())
}
async fn replay_pending(&self) -> Result<usize, String> {
Ok(0)
}
}
#[cfg(test)]
mod tests {
use super::*;
struct CountHandler {
count: parking_lot::Mutex<usize>,
}
#[async_trait]
impl EventHandler for CountHandler {
async fn handle(&self, _event: &PluginEvent) -> Result<(), String> {
*self.count.lock() += 1;
Ok(())
}
}
#[tokio::test]
async fn test_publish_and_subscribe() {
let bus = InMemoryEventBus::new();
let handler = Arc::new(CountHandler {
count: parking_lot::Mutex::new(0),
});
let _ = bus.subscribe("test.event", handler.clone()).await;
let event = PluginEvent {
id: 0,
tenant_id: 1,
event_type: "test.event".to_string(),
source_plugin: "test".to_string(),
payload: serde_json::json!({}),
};
let id = bus.publish(&event).await.expect("发布失败");
assert!(id > 0);
assert_eq!(*handler.count.lock(), 1);
}
}