1use crate::types::EntityId;
4use flume::{Receiver, Sender, unbounded};
5use serde::Serialize;
6use std::{
7 sync::{Arc, Mutex, atomic::AtomicBool},
8 thread,
9};
10
11#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
12pub enum EntityEvent {
13 Created,
14 Updated,
15 Removed,
16}
17
18#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
19pub enum AllEvent {
20 Reset,
21}
22
23#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
24pub enum UndoRedoEvent {
25 Undone,
26 Redone,
27 BeginComposite,
28 EndComposite,
29 CancelComposite,
30}
31
32#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
33pub enum LongOperationEvent {
34 Started,
35 Progress,
36 Cancelled,
37 Completed,
38 Failed,
39}
40
41#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
42pub enum DirectAccessEntity {
43 All(AllEvent),
44
45 Root(EntityEvent),
46 Workspace(EntityEvent),
47 System(EntityEvent),
48 Entity(EntityEvent),
49 Field(EntityEvent),
50 Feature(EntityEvent),
51 File(EntityEvent),
52 UseCase(EntityEvent),
53 Dto(EntityEvent),
54 DtoField(EntityEvent),
55 Global(EntityEvent),
56 Relationship(EntityEvent),
57 UserInterface(EntityEvent),
58}
59
60#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
61pub enum HandlingAppLifecycleEvent {
62 InitializeApp,
63 CleanUpBeforeExit,
64}
65
66#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
67pub enum HandlingManifestEvent {
68 Load,
69 Save,
70 Create,
71 Close,
72 ExportToMermaid,
73 Check,
74}
75
76#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
77pub enum RustFileGenerationEvent {
78 FillRustFiles,
79 FillCodeInRustFiles,
80 GenerateRustCode,
81 GenerateRustFiles,
82 GenerateRustPrompt,
83}
84
85#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
86pub enum CppQtFileGenerationEvent {
87 FillCppQtFiles,
88 GenerateCppQtCode,
89 GenerateCppQtFiles,
90 FillCodeInCppQtFiles,
91 GenerateCppQtPrompt,
92}
93
94#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
95pub enum FileGenerationSharedStepsEvent {
96 FillStatusInFiles,
97 GetFileDiff,
98}
99
100#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
101pub enum Origin {
102 DirectAccess(DirectAccessEntity),
103 UndoRedo(UndoRedoEvent),
104 LongOperation(LongOperationEvent),
105
106 HandlingAppLifecycle(HandlingAppLifecycleEvent),
107 HandlingManifest(HandlingManifestEvent),
108 RustFileGeneration(RustFileGenerationEvent),
109 CppQtFileGeneration(CppQtFileGenerationEvent),
110 FileGenerationSharedSteps(FileGenerationSharedStepsEvent),
111}
112
113#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
114pub struct Event {
115 pub origin: Origin,
116 pub ids: Vec<EntityId>,
117 pub data: Option<String>,
118}
119
120impl Event {
121 pub fn origin_string(&self) -> String {
122 match &self.origin {
123 Origin::DirectAccess(entity) => match entity {
124 DirectAccessEntity::All(event) => format!("direct_access_all_{:?}", event),
125 DirectAccessEntity::Root(event) => format!("direct_access_root_{:?}", event),
127 DirectAccessEntity::Workspace(event) => {
128 format!("direct_access_workspace_{:?}", event)
129 }
130 DirectAccessEntity::System(event) => format!("direct_access_system_{:?}", event),
131 DirectAccessEntity::Entity(event) => format!("direct_access_entity_{:?}", event),
132 DirectAccessEntity::Field(event) => format!("direct_access_field_{:?}", event),
133 DirectAccessEntity::Feature(event) => format!("direct_access_feature_{:?}", event),
134 DirectAccessEntity::File(event) => format!("direct_access_file_{:?}", event),
135 DirectAccessEntity::UseCase(event) => format!("direct_access_use_case_{:?}", event),
136 DirectAccessEntity::Dto(event) => format!("direct_access_dto_{:?}", event),
137 DirectAccessEntity::DtoField(event) => {
138 format!("direct_access_dto_field_{:?}", event)
139 }
140 DirectAccessEntity::Global(event) => format!("direct_access_global_{:?}", event),
141 DirectAccessEntity::Relationship(event) => {
142 format!("direct_access_relationship_{:?}", event)
143 }
144 DirectAccessEntity::UserInterface(event) => {
145 format!("direct_access_user_interface_{:?}", event)
146 }
147 },
148 Origin::UndoRedo(event) => format!("undo_redo_{:?}", event),
149 Origin::LongOperation(event) => format!("long_operation_{:?}", event),
150 Origin::HandlingAppLifecycle(event) => format!("handling_app_lifecycle_{:?}", event),
152 Origin::HandlingManifest(event) => format!("handling_manifest_{:?}", event),
153 Origin::RustFileGeneration(event) => format!("rust_file_generation_{:?}", event),
154 Origin::CppQtFileGeneration(event) => format!("cpp_qt_file_generation_{:?}", event),
155 Origin::FileGenerationSharedSteps(event) => {
156 format!("file_generation_shared_steps_{:?}", event)
157 }
158 }
159 .to_lowercase()
160 }
161}
162pub struct EventBuffer {
171 buffering: bool,
172 pending: Vec<Event>,
173}
174
175impl EventBuffer {
176 pub fn new() -> Self {
177 Self {
178 buffering: false,
179 pending: Vec::new(),
180 }
181 }
182
183 pub fn begin_buffering(&mut self) {
185 self.buffering = true;
186 self.pending.clear();
187 }
188
189 pub fn push(&mut self, event: Event) {
194 if self.buffering {
195 self.pending.push(event);
196 }
197 }
198
199 pub fn flush(&mut self) -> Vec<Event> {
202 self.buffering = false;
203 std::mem::take(&mut self.pending)
204 }
205
206 pub fn discard(&mut self) {
208 self.buffering = false;
209 self.pending.clear();
210 }
211
212 pub fn is_buffering(&self) -> bool {
213 self.buffering
214 }
215}
216
217impl Default for EventBuffer {
218 fn default() -> Self {
219 Self::new()
220 }
221}
222
223pub type Queue = Arc<Mutex<Vec<Event>>>;
224
225pub struct EventHub {
227 sender: Sender<Event>,
228 receiver: Receiver<Event>,
229 queue: Queue,
230}
231
232impl Default for EventHub {
233 fn default() -> Self {
234 Self::new()
235 }
236}
237
238impl EventHub {
239 pub fn new() -> Self {
241 let (sender, receiver) = unbounded();
242 EventHub {
243 sender,
244 receiver,
245 queue: Arc::new(Mutex::new(Vec::new())),
246 }
247 }
248
249 pub fn start_event_loop(&self, stop_signal: Arc<AtomicBool>) -> thread::JoinHandle<()> {
255 let receiver = self.receiver.clone();
256 let queue = self.queue.clone();
257 thread::spawn(move || {
258 loop {
259 if stop_signal.load(std::sync::atomic::Ordering::Relaxed) {
260 break;
261 }
262
263 match receiver.recv_timeout(std::time::Duration::from_millis(100)) {
264 Ok(event) => {
265 let mut queue = queue.lock().unwrap();
266 queue.push(event.clone());
267 }
268 Err(flume::RecvTimeoutError::Timeout) => {
269 continue;
271 }
272 Err(flume::RecvTimeoutError::Disconnected) => {
273 break;
274 }
275 };
276 }
277 })
278 }
279
280 pub fn send_event(&self, event: Event) {
282 if let Err(e) = self.sender.send(event) {
283 eprintln!("EventHub: failed to send event (receiver dropped): {e}");
284 }
285 }
286
287 pub fn get_queue(&self) -> Queue {
288 self.queue.clone()
289 }
290
291 pub fn subscribe_receiver(&self) -> Receiver<Event> {
297 self.receiver.clone()
298 }
299}
300
301#[cfg(test)]
302mod tests {
303 use super::*;
304
305 #[test]
306 fn test_event_hub_send_and_receive() {
307 let event_hub = EventHub::new();
308 let stop_signal = Arc::new(AtomicBool::new(false));
309 let _handle = event_hub.start_event_loop(stop_signal.clone());
310
311 let event = Event {
312 origin: Origin::DirectAccess(DirectAccessEntity::All(AllEvent::Reset)),
313 ids: vec![EntityId::default()],
314 data: Some("test_data".to_string()),
315 };
316
317 event_hub.send_event(event.clone());
318
319 thread::sleep(std::time::Duration::from_millis(100));
320
321 let queue = event_hub.get_queue();
322 let queue = queue.lock().unwrap();
323 assert_eq!(queue.len(), 1);
324 assert_eq!(queue[0], event);
325
326 stop_signal.store(true, std::sync::atomic::Ordering::Relaxed);
327 }
328}