text_document_frontend/
event_hub_client.rs1use common::event::{Event, EventHub, Origin};
3use flume::Receiver;
4use std::collections::HashMap;
5use std::sync::atomic::{AtomicU64, Ordering};
6use std::sync::{Arc, Mutex};
7use std::thread;
8
9pub type EventCallback = Box<dyn Fn(Event) + Send>;
11
12type SubscriberList = Vec<(u64, EventCallback)>;
16
17#[derive(Clone)]
20pub struct EventHubClient {
21 subscribers: Arc<Mutex<HashMap<Origin, SubscriberList>>>,
22 receiver: Receiver<Event>,
23 next_subscriber_id: Arc<AtomicU64>,
24}
25
26impl EventHubClient {
27 pub fn new(event_hub: &EventHub) -> Self {
29 EventHubClient {
30 subscribers: Arc::new(Mutex::new(HashMap::new())),
31 receiver: event_hub.subscribe_receiver(),
32 next_subscriber_id: Arc::new(AtomicU64::new(0)),
33 }
34 }
35
36 pub fn subscribe<F>(&self, origin: Origin, callback: F) -> SubscriptionToken
41 where
42 F: Fn(Event) + Send + 'static,
43 {
44 let id = self.next_subscriber_id.fetch_add(1, Ordering::Relaxed);
45 {
46 let mut subs = self.subscribers.lock().unwrap();
47 subs.entry(origin.clone())
48 .or_default()
49 .push((id, Box::new(callback)));
50 }
51 SubscriptionToken {
52 subscribers: Arc::clone(&self.subscribers),
53 origin,
54 id,
55 }
56 }
57
58 pub fn start(&self, quit_signal: Arc<std::sync::atomic::AtomicBool>) {
61 let receiver = self.receiver.clone();
62 let subscribers = Arc::clone(&self.subscribers);
63 let quit_signal = Arc::clone(&quit_signal);
64
65 log::info!("EventHubClient starting event loop");
66
67 thread::spawn(move || {
68 log::info!("EventHubClient event loop started");
69 loop {
70 match receiver.recv_timeout(std::time::Duration::from_millis(200)) {
71 Ok(event) => {
72 log::debug!("EventHubClient received event: {:?}", event);
73 let subs = subscribers.lock().unwrap();
74 if let Some(callbacks) = subs.get(&event.origin) {
75 for (_id, callback) in callbacks {
76 callback(event.clone());
77 }
78 }
79 }
80 Err(flume::RecvTimeoutError::Timeout) => {
81 }
83 Err(flume::RecvTimeoutError::Disconnected) => {
84 log::info!("EventHubClient channel disconnected");
85 break;
86 }
87 }
88
89 if quit_signal.load(std::sync::atomic::Ordering::Relaxed) {
90 log::info!("EventHubClient quitting event loop");
91 break;
92 }
93 }
94 });
95 }
96}
97
98pub struct SubscriptionToken {
102 subscribers: Arc<Mutex<HashMap<Origin, SubscriberList>>>,
103 origin: Origin,
104 id: u64,
105}
106
107impl Drop for SubscriptionToken {
108 fn drop(&mut self) {
109 if let Ok(mut subs) = self.subscribers.lock()
112 && let Some(list) = subs.get_mut(&self.origin)
113 {
114 list.retain(|(id, _)| *id != self.id);
115 if list.is_empty() {
116 subs.remove(&self.origin);
117 }
118 }
119 }
120}