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 #[must_use]
60 pub fn new(
61 workspace_id: Uuid,
62 change_type: ChangeType,
63 user_id: Uuid,
64 resource_id: Option<Uuid>,
65 payload: serde_json::Value,
66 ) -> Self {
67 Self {
68 id: Uuid::new_v4(),
69 workspace_id,
70 change_type,
71 user_id,
72 resource_id,
73 payload,
74 timestamp: Utc::now(),
75 }
76 }
77}
78
79#[async_trait::async_trait]
81pub trait EventListener: Send + Sync {
82 async fn on_event(&self, event: ChangeEvent) -> Result<()>;
84}
85
86pub struct EventBus {
88 sender: broadcast::Sender<ChangeEvent>,
90}
91
92impl EventBus {
93 #[must_use]
95 pub fn new(capacity: usize) -> Self {
96 let (sender, _) = broadcast::channel(capacity);
97 Self { sender }
98 }
99
100 pub fn publish(&self, event: ChangeEvent) -> Result<()> {
106 let _ = self.sender.send(event);
108 Ok(())
109 }
110
111 #[must_use]
113 pub fn subscribe(&self) -> broadcast::Receiver<ChangeEvent> {
114 self.sender.subscribe()
115 }
116
117 #[must_use]
119 pub fn subscriber_count(&self) -> usize {
120 self.sender.receiver_count()
121 }
122}
123
124pub struct WorkspaceEventBus {
126 event_bus: Arc<EventBus>,
128 workspace_id: Uuid,
130}
131
132impl WorkspaceEventBus {
133 #[must_use]
135 pub const fn new(event_bus: Arc<EventBus>, workspace_id: Uuid) -> Self {
136 Self {
137 event_bus,
138 workspace_id,
139 }
140 }
141
142 pub fn publish(
148 &self,
149 change_type: ChangeType,
150 user_id: Uuid,
151 resource_id: Option<Uuid>,
152 payload: serde_json::Value,
153 ) -> Result<()> {
154 let event = ChangeEvent::new(self.workspace_id, change_type, user_id, resource_id, payload);
155 self.event_bus.publish(event)
156 }
157
158 #[must_use]
160 pub fn subscribe(&self) -> broadcast::Receiver<ChangeEvent> {
161 self.event_bus.subscribe()
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn test_change_event_creation() {
171 let workspace_id = Uuid::new_v4();
172 let user_id = Uuid::new_v4();
173 let event = ChangeEvent::new(
174 workspace_id,
175 ChangeType::MockCreated,
176 user_id,
177 None,
178 serde_json::json!({"mock_id": "123"}),
179 );
180
181 assert_eq!(event.workspace_id, workspace_id);
182 assert_eq!(event.change_type, ChangeType::MockCreated);
183 assert_eq!(event.user_id, user_id);
184 }
185
186 #[test]
187 fn test_event_bus() {
188 let bus = EventBus::new(100);
189 assert_eq!(bus.subscriber_count(), 0);
190
191 let _rx1 = bus.subscribe();
192 assert_eq!(bus.subscriber_count(), 1);
193
194 let _rx2 = bus.subscribe();
195 assert_eq!(bus.subscriber_count(), 2);
196 }
197
198 #[tokio::test]
199 async fn test_event_publishing() {
200 let bus = EventBus::new(100);
201 let mut rx = bus.subscribe();
202
203 let workspace_id = Uuid::new_v4();
204 let user_id = Uuid::new_v4();
205 let event = ChangeEvent::new(
206 workspace_id,
207 ChangeType::MockCreated,
208 user_id,
209 None,
210 serde_json::json!({}),
211 );
212
213 bus.publish(event.clone()).unwrap();
214
215 let received = rx.recv().await.unwrap();
216 assert_eq!(received.workspace_id, workspace_id);
217 assert_eq!(received.change_type, ChangeType::MockCreated);
218 }
219}