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<()> {
102 let _ = self.sender.send(event);
104 Ok(())
105 }
106
107 #[must_use]
109 pub fn subscribe(&self) -> broadcast::Receiver<ChangeEvent> {
110 self.sender.subscribe()
111 }
112
113 #[must_use]
115 pub fn subscriber_count(&self) -> usize {
116 self.sender.receiver_count()
117 }
118}
119
120pub struct WorkspaceEventBus {
122 event_bus: Arc<EventBus>,
124 workspace_id: Uuid,
126}
127
128impl WorkspaceEventBus {
129 #[must_use]
131 pub const fn new(event_bus: Arc<EventBus>, workspace_id: Uuid) -> Self {
132 Self {
133 event_bus,
134 workspace_id,
135 }
136 }
137
138 pub fn publish(
140 &self,
141 change_type: ChangeType,
142 user_id: Uuid,
143 resource_id: Option<Uuid>,
144 payload: serde_json::Value,
145 ) -> Result<()> {
146 let event = ChangeEvent::new(self.workspace_id, change_type, user_id, resource_id, payload);
147 self.event_bus.publish(event)
148 }
149
150 #[must_use]
152 pub fn subscribe(&self) -> broadcast::Receiver<ChangeEvent> {
153 self.event_bus.subscribe()
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[test]
162 fn test_change_event_creation() {
163 let workspace_id = Uuid::new_v4();
164 let user_id = Uuid::new_v4();
165 let event = ChangeEvent::new(
166 workspace_id,
167 ChangeType::MockCreated,
168 user_id,
169 None,
170 serde_json::json!({"mock_id": "123"}),
171 );
172
173 assert_eq!(event.workspace_id, workspace_id);
174 assert_eq!(event.change_type, ChangeType::MockCreated);
175 assert_eq!(event.user_id, user_id);
176 }
177
178 #[test]
179 fn test_event_bus() {
180 let bus = EventBus::new(100);
181 assert_eq!(bus.subscriber_count(), 0);
182
183 let _rx1 = bus.subscribe();
184 assert_eq!(bus.subscriber_count(), 1);
185
186 let _rx2 = bus.subscribe();
187 assert_eq!(bus.subscriber_count(), 2);
188 }
189
190 #[tokio::test]
191 async fn test_event_publishing() {
192 let bus = EventBus::new(100);
193 let mut rx = bus.subscribe();
194
195 let workspace_id = Uuid::new_v4();
196 let user_id = Uuid::new_v4();
197 let event = ChangeEvent::new(
198 workspace_id,
199 ChangeType::MockCreated,
200 user_id,
201 None,
202 serde_json::json!({}),
203 );
204
205 bus.publish(event.clone()).unwrap();
206
207 let received = rx.recv().await.unwrap();
208 assert_eq!(received.workspace_id, workspace_id);
209 assert_eq!(received.change_type, ChangeType::MockCreated);
210 }
211}