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 Document(EntityEvent),
47 Frame(EntityEvent),
48 Block(EntityEvent),
49 InlineElement(EntityEvent),
50 List(EntityEvent),
51 Resource(EntityEvent),
52}
53
54#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
55pub enum DocumentEditingEvent {
56 InsertText,
57 DeleteText,
58 InsertBlock,
59 InsertImage,
60 InsertFrame,
61 InsertFormattedText,
62 CreateList,
63 InsertList,
64 InsertFragment,
65 InsertHtmlAtPosition,
66 InsertMarkdownAtPosition,
67}
68
69#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
70pub enum DocumentFormattingEvent {
71 SetTextFormat,
72 MergeTextFormat,
73 SetBlockFormat,
74 SetFrameFormat,
75}
76
77#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
78pub enum DocumentIoEvent {
79 ImportPlainText,
80 ExportPlainText,
81 ImportMarkdown,
82 ExportMarkdown,
83 ImportHtml,
84 ExportHtml,
85 ExportLatex,
86 ExportDocx,
87}
88
89#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
90pub enum DocumentSearchEvent {
91 FindText,
92 FindAll,
93 ReplaceText,
94}
95
96#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
97pub enum DocumentInspectionEvent {
98 GetDocumentStats,
99 GetTextAtPosition,
100 GetBlockAtPosition,
101 ExtractFragment,
102}
103
104#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
105pub enum Origin {
106 DirectAccess(DirectAccessEntity),
107 UndoRedo(UndoRedoEvent),
108 LongOperation(LongOperationEvent),
109
110 DocumentEditing(DocumentEditingEvent),
111 DocumentFormatting(DocumentFormattingEvent),
112 DocumentIo(DocumentIoEvent),
113 DocumentSearch(DocumentSearchEvent),
114 DocumentInspection(DocumentInspectionEvent),
115}
116
117#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
118pub struct Event {
119 pub origin: Origin,
120 pub ids: Vec<EntityId>,
121 pub data: Option<String>,
122}
123
124impl Event {
125 pub fn origin_string(&self) -> String {
126 match &self.origin {
127 Origin::DirectAccess(entity) => match entity {
128 DirectAccessEntity::All(event) => format!("direct_access_all_{:?}", event),
129 DirectAccessEntity::Root(event) => format!("direct_access_root_{:?}", event),
131 DirectAccessEntity::Document(event) => {
132 format!("direct_access_document_{:?}", event)
133 }
134 DirectAccessEntity::Frame(event) => format!("direct_access_frame_{:?}", event),
135 DirectAccessEntity::Block(event) => format!("direct_access_block_{:?}", event),
136 DirectAccessEntity::InlineElement(event) => {
137 format!("direct_access_inline_element_{:?}", event)
138 }
139 DirectAccessEntity::List(event) => format!("direct_access_list_{:?}", event),
140 DirectAccessEntity::Resource(event) => {
141 format!("direct_access_resource_{:?}", event)
142 }
143 },
144 Origin::UndoRedo(event) => format!("undo_redo_{:?}", event),
145 Origin::LongOperation(event) => format!("long_operation_{:?}", event),
146 Origin::DocumentEditing(event) => format!("document_editing_{:?}", event),
148 Origin::DocumentFormatting(event) => format!("document_formatting_{:?}", event),
149 Origin::DocumentIo(event) => format!("document_io_{:?}", event),
150 Origin::DocumentSearch(event) => format!("document_search_{:?}", event),
151 Origin::DocumentInspection(event) => format!("document_inspection_{:?}", event),
152 }
153 .to_lowercase()
154 }
155}
156pub struct EventBuffer {
165 buffering: bool,
166 pending: Vec<Event>,
167}
168
169impl EventBuffer {
170 pub fn new() -> Self {
171 Self {
172 buffering: false,
173 pending: Vec::new(),
174 }
175 }
176
177 pub fn begin_buffering(&mut self) {
179 self.buffering = true;
180 self.pending.clear();
181 }
182
183 pub fn push(&mut self, event: Event) {
188 if self.buffering {
189 self.pending.push(event);
190 }
191 }
192
193 pub fn flush(&mut self) -> Vec<Event> {
196 self.buffering = false;
197 std::mem::take(&mut self.pending)
198 }
199
200 pub fn discard(&mut self) {
202 self.buffering = false;
203 self.pending.clear();
204 }
205
206 pub fn is_buffering(&self) -> bool {
207 self.buffering
208 }
209}
210
211impl Default for EventBuffer {
212 fn default() -> Self {
213 Self::new()
214 }
215}
216
217pub type Queue = Arc<Mutex<Vec<Event>>>;
218
219pub struct EventHub {
221 sender: Sender<Event>,
222 receiver: Receiver<Event>,
223 queue: Queue,
224}
225
226impl Default for EventHub {
227 fn default() -> Self {
228 Self::new()
229 }
230}
231
232impl EventHub {
233 pub fn new() -> Self {
235 let (sender, receiver) = unbounded();
236 EventHub {
237 sender,
238 receiver,
239 queue: Arc::new(Mutex::new(Vec::new())),
240 }
241 }
242
243 pub fn start_event_loop(&self, stop_signal: Arc<AtomicBool>) -> thread::JoinHandle<()> {
249 let receiver = self.receiver.clone();
250 let queue = self.queue.clone();
251 thread::spawn(move || {
252 loop {
253 if stop_signal.load(std::sync::atomic::Ordering::Relaxed) {
254 break;
255 }
256
257 match receiver.recv_timeout(std::time::Duration::from_millis(100)) {
258 Ok(event) => {
259 let mut queue = queue.lock().unwrap();
260 queue.push(event.clone());
261 }
262 Err(flume::RecvTimeoutError::Timeout) => {
263 continue;
265 }
266 Err(flume::RecvTimeoutError::Disconnected) => {
267 break;
268 }
269 };
270 }
271 })
272 }
273
274 pub fn send_event(&self, event: Event) {
276 if let Err(e) = self.sender.send(event) {
277 eprintln!("EventHub: failed to send event (receiver dropped): {e}");
278 }
279 }
280
281 pub fn get_queue(&self) -> Queue {
282 self.queue.clone()
283 }
284
285 pub fn subscribe_receiver(&self) -> Receiver<Event> {
292 self.receiver.clone()
293 }
294}
295
296#[cfg(test)]
297mod tests {
298 use super::*;
299
300 #[test]
301 fn test_event_hub_send_and_receive() {
302 let event_hub = EventHub::new();
303 let stop_signal = Arc::new(AtomicBool::new(false));
304 let _handle = event_hub.start_event_loop(stop_signal.clone());
305
306 let event = Event {
307 origin: Origin::DirectAccess(DirectAccessEntity::All(AllEvent::Reset)),
308 ids: vec![EntityId::default()],
309 data: Some("test_data".to_string()),
310 };
311
312 event_hub.send_event(event.clone());
313
314 thread::sleep(std::time::Duration::from_millis(100));
315
316 let queue = event_hub.get_queue();
317 let queue = queue.lock().unwrap();
318 assert_eq!(queue.len(), 1);
319 assert_eq!(queue[0], event);
320
321 stop_signal.store(true, std::sync::atomic::Ordering::Relaxed);
322 }
323}