mockforge_collab/
events.rs1use crate::error::Result;
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use std::sync::Arc;
7use tokio::sync::broadcast;
8use uuid::Uuid;
9
10#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
12#[serde(rename_all = "snake_case")]
13pub enum ChangeType {
14 MockCreated,
16 MockUpdated,
18 MockDeleted,
20 WorkspaceUpdated,
22 MemberAdded,
24 MemberRemoved,
26 RoleChanged,
28 SnapshotCreated,
30 CursorMoved,
32 UserJoined,
34 UserLeft,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct ChangeEvent {
41 pub id: Uuid,
43 pub workspace_id: Uuid,
45 pub change_type: ChangeType,
47 pub user_id: Uuid,
49 pub resource_id: Option<Uuid>,
51 pub payload: serde_json::Value,
53 pub timestamp: DateTime<Utc>,
55}
56
57impl ChangeEvent {
58 pub fn new(
60 workspace_id: Uuid,
61 change_type: ChangeType,
62 user_id: Uuid,
63 resource_id: Option<Uuid>,
64 payload: serde_json::Value,
65 ) -> Self {
66 Self {
67 id: Uuid::new_v4(),
68 workspace_id,
69 change_type,
70 user_id,
71 resource_id,
72 payload,
73 timestamp: Utc::now(),
74 }
75 }
76}
77
78#[async_trait::async_trait]
80pub trait EventListener: Send + Sync {
81 async fn on_event(&self, event: ChangeEvent) -> Result<()>;
83}
84
85pub struct EventBus {
87 sender: broadcast::Sender<ChangeEvent>,
89}
90
91impl EventBus {
92 pub fn new(capacity: usize) -> Self {
94 let (sender, _) = broadcast::channel(capacity);
95 Self { sender }
96 }
97
98 pub fn publish(&self, event: ChangeEvent) -> Result<()> {
100 let _ = self.sender.send(event);
102 Ok(())
103 }
104
105 pub fn subscribe(&self) -> broadcast::Receiver<ChangeEvent> {
107 self.sender.subscribe()
108 }
109
110 pub fn subscriber_count(&self) -> usize {
112 self.sender.receiver_count()
113 }
114}
115
116pub struct WorkspaceEventBus {
118 event_bus: Arc<EventBus>,
120 workspace_id: Uuid,
122}
123
124impl WorkspaceEventBus {
125 pub fn new(event_bus: Arc<EventBus>, workspace_id: Uuid) -> Self {
127 Self {
128 event_bus,
129 workspace_id,
130 }
131 }
132
133 pub fn publish(
135 &self,
136 change_type: ChangeType,
137 user_id: Uuid,
138 resource_id: Option<Uuid>,
139 payload: serde_json::Value,
140 ) -> Result<()> {
141 let event = ChangeEvent::new(self.workspace_id, change_type, user_id, resource_id, payload);
142 self.event_bus.publish(event)
143 }
144
145 pub fn subscribe(&self) -> broadcast::Receiver<ChangeEvent> {
147 self.event_bus.subscribe()
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn test_change_event_creation() {
157 let workspace_id = Uuid::new_v4();
158 let user_id = Uuid::new_v4();
159 let event = ChangeEvent::new(
160 workspace_id,
161 ChangeType::MockCreated,
162 user_id,
163 None,
164 serde_json::json!({"mock_id": "123"}),
165 );
166
167 assert_eq!(event.workspace_id, workspace_id);
168 assert_eq!(event.change_type, ChangeType::MockCreated);
169 assert_eq!(event.user_id, user_id);
170 }
171
172 #[test]
173 fn test_event_bus() {
174 let bus = EventBus::new(100);
175 assert_eq!(bus.subscriber_count(), 0);
176
177 let _rx1 = bus.subscribe();
178 assert_eq!(bus.subscriber_count(), 1);
179
180 let _rx2 = bus.subscribe();
181 assert_eq!(bus.subscriber_count(), 2);
182 }
183
184 #[tokio::test]
185 async fn test_event_publishing() {
186 let bus = EventBus::new(100);
187 let mut rx = bus.subscribe();
188
189 let workspace_id = Uuid::new_v4();
190 let user_id = Uuid::new_v4();
191 let event = ChangeEvent::new(
192 workspace_id,
193 ChangeType::MockCreated,
194 user_id,
195 None,
196 serde_json::json!({}),
197 );
198
199 bus.publish(event.clone()).unwrap();
200
201 let received = rx.recv().await.unwrap();
202 assert_eq!(received.workspace_id, workspace_id);
203 assert_eq!(received.change_type, ChangeType::MockCreated);
204 }
205}