1use crate::types::EntityId;
4use flume::{Receiver, Sender, unbounded};
5use serde::Serialize;
6use std::{
7 sync::{Arc, Mutex},
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 StackChanged,
36 BeginComposite,
37 EndComposite,
38 CancelComposite,
39}
40
41#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
42pub enum LongOperationEvent {
43 Started,
44 Progress,
45 Cancelled,
46 Completed,
47 Failed,
48}
49
50#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
51pub enum DirectAccessEntity {
52 All(AllEvent),
53
54 Root(EntityEvent),
55 Workspace(EntityEvent),
56 System(EntityEvent),
57 Entity(EntityEvent),
58 Field(EntityEvent),
59 Feature(EntityEvent),
60 File(EntityEvent),
61 UseCase(EntityEvent),
62 Dto(EntityEvent),
63 DtoField(EntityEvent),
64 Global(EntityEvent),
65 Relationship(EntityEvent),
66 UserInterface(EntityEvent),
67}
68
69#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
70pub enum HandlingAppLifecycleEvent {
71 InitializeApp,
72 CleanUpBeforeExit,
73}
74
75#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
76pub enum HandlingManifestEvent {
77 Load,
78 Save,
79 Create,
80 Close,
81 ExportToMermaid,
82 Check,
83}
84
85#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
86pub enum RustFileGenerationEvent {
87 FillRustFiles,
88 FillCodeInRustFiles,
89 GenerateRustCode,
90 GenerateRustFiles,
91 GenerateRustPrompt,
92}
93
94#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
95pub enum CppQtFileGenerationEvent {
96 FillCppQtFiles,
97 GenerateCppQtCode,
98 GenerateCppQtFiles,
99 FillCodeInCppQtFiles,
100 GenerateCppQtPrompt,
101}
102
103#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
104pub enum FileGenerationSharedStepsEvent {
105 FillStatusInFiles,
106 GetFileDiff,
107}
108
109#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
110pub enum Origin {
111 DirectAccess(DirectAccessEntity),
112 UndoRedo(UndoRedoEvent),
113 LongOperation(LongOperationEvent),
114
115 HandlingAppLifecycle(HandlingAppLifecycleEvent),
116 HandlingManifest(HandlingManifestEvent),
117 RustFileGeneration(RustFileGenerationEvent),
118 CppQtFileGeneration(CppQtFileGenerationEvent),
119 FileGenerationSharedSteps(FileGenerationSharedStepsEvent),
120}
121
122#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
123pub struct Event {
124 pub origin: Origin,
125 pub ids: Vec<EntityId>,
126 pub data: Option<String>,
127}
128
129impl Event {
130 pub fn origin_string(&self) -> String {
131 match &self.origin {
132 Origin::DirectAccess(entity) => match entity {
133 DirectAccessEntity::All(event) => format!("direct_access_all_{:?}", event),
134 DirectAccessEntity::Root(event) => format!("direct_access_root_{:?}", event),
136 DirectAccessEntity::Workspace(event) => {
137 format!("direct_access_workspace_{:?}", event)
138 }
139 DirectAccessEntity::System(event) => format!("direct_access_system_{:?}", event),
140 DirectAccessEntity::Entity(event) => format!("direct_access_entity_{:?}", event),
141 DirectAccessEntity::Field(event) => format!("direct_access_field_{:?}", event),
142 DirectAccessEntity::Feature(event) => format!("direct_access_feature_{:?}", event),
143 DirectAccessEntity::File(event) => format!("direct_access_file_{:?}", event),
144 DirectAccessEntity::UseCase(event) => format!("direct_access_use_case_{:?}", event),
145 DirectAccessEntity::Dto(event) => format!("direct_access_dto_{:?}", event),
146 DirectAccessEntity::DtoField(event) => {
147 format!("direct_access_dto_field_{:?}", event)
148 }
149 DirectAccessEntity::Global(event) => format!("direct_access_global_{:?}", event),
150 DirectAccessEntity::Relationship(event) => {
151 format!("direct_access_relationship_{:?}", event)
152 }
153 DirectAccessEntity::UserInterface(event) => {
154 format!("direct_access_user_interface_{:?}", event)
155 }
156 },
157 Origin::UndoRedo(event) => format!("undo_redo_{:?}", event),
158 Origin::LongOperation(event) => format!("long_operation_{:?}", event),
159 Origin::HandlingAppLifecycle(event) => format!("handling_app_lifecycle_{:?}", event),
161 Origin::HandlingManifest(event) => format!("handling_manifest_{:?}", event),
162 Origin::RustFileGeneration(event) => format!("rust_file_generation_{:?}", event),
163 Origin::CppQtFileGeneration(event) => format!("cpp_qt_file_generation_{:?}", event),
164 Origin::FileGenerationSharedSteps(event) => {
165 format!("file_generation_shared_steps_{:?}", event)
166 }
167 }
168 .to_lowercase()
169 }
170}
171pub struct EventBuffer {
180 buffering: bool,
181 pending: Vec<Event>,
182}
183
184impl EventBuffer {
185 pub fn new() -> Self {
186 Self {
187 buffering: false,
188 pending: Vec::new(),
189 }
190 }
191
192 pub fn begin_buffering(&mut self) {
194 self.buffering = true;
195 self.pending.clear();
196 }
197
198 pub fn push(&mut self, event: Event) {
203 if self.buffering {
204 self.pending.push(event);
205 }
206 }
207
208 pub fn flush(&mut self) -> Vec<Event> {
211 self.buffering = false;
212 std::mem::take(&mut self.pending)
213 }
214
215 pub fn discard(&mut self) {
217 self.buffering = false;
218 self.pending.clear();
219 }
220
221 pub fn is_buffering(&self) -> bool {
222 self.buffering
223 }
224}
225
226impl Default for EventBuffer {
227 fn default() -> Self {
228 Self::new()
229 }
230}
231
232pub type Queue = Arc<Mutex<Vec<Event>>>;
233
234#[derive(Debug)]
236pub struct EventHub {
237 sender: Sender<Event>,
238 receiver: Receiver<Event>,
239 queue: Queue,
240}
241
242impl Default for EventHub {
243 fn default() -> Self {
244 Self::new()
245 }
246}
247
248impl EventHub {
249 pub fn new() -> Self {
251 let (sender, receiver) = unbounded();
252 EventHub {
253 sender,
254 receiver,
255 queue: Arc::new(Mutex::new(Vec::new())),
256 }
257 }
258
259 pub fn start_event_loop(&self, shutdown_rx: Receiver<()>) -> thread::JoinHandle<()> {
267 let receiver = self.receiver.clone();
268 let queue = self.queue.clone();
269 thread::spawn(move || {
270 loop {
271 let outcome: Result<Option<Event>, ()> = flume::Selector::new()
272 .recv(&receiver, |r| r.map(Some).map_err(|_| ()))
273 .recv(&shutdown_rx, |_| Ok(None))
274 .wait();
275 match outcome {
276 Ok(Some(event)) => {
277 let mut queue = crate::long_operation::lock_or_recover(&queue);
278 queue.push(event);
279 }
280 Ok(None) | Err(()) => break,
281 }
282 }
283 })
284 }
285
286 pub fn send_event(&self, event: Event) {
288 if let Err(e) = self.sender.send(event) {
289 eprintln!("EventHub: failed to send event (receiver dropped): {e}");
290 }
291 }
292
293 pub fn get_queue(&self) -> Queue {
294 self.queue.clone()
295 }
296
297 pub fn subscribe_receiver(&self) -> Receiver<Event> {
304 self.receiver.clone()
305 }
306}
307
308#[cfg(test)]
309mod tests {
310 use super::*;
311
312 #[test]
313 fn test_event_hub_send_and_receive() {
314 let event_hub = EventHub::new();
315 let (shutdown_tx, shutdown_rx) = flume::bounded::<()>(1);
316 let handle = event_hub.start_event_loop(shutdown_rx);
317
318 let event = Event {
319 origin: Origin::DirectAccess(DirectAccessEntity::All(AllEvent::Reset)),
320 ids: vec![EntityId::default()],
321 data: Some("test_data".to_string()),
322 };
323
324 event_hub.send_event(event.clone());
325
326 thread::sleep(std::time::Duration::from_millis(100));
327
328 let queue = event_hub.get_queue();
329 let queue = crate::long_operation::lock_or_recover(&queue);
330 assert_eq!(queue.len(), 1);
331 assert_eq!(queue[0], event);
332
333 drop(shutdown_tx);
335 handle.join().unwrap();
336 }
337}