dx_forge/api/
reactivity.rs1use anyhow::Result;
4use std::sync::{Arc, OnceLock};
5use parking_lot::RwLock;
6use tokio::time::{Duration, sleep};
7use std::path::PathBuf;
8
9static REACTIVITY_STATE: OnceLock<Arc<RwLock<ReactivityState>>> = OnceLock::new();
11
12struct ReactivityState {
13 in_batch: bool,
14 batch_start: Option<std::time::Instant>,
15}
16
17impl Default for ReactivityState {
18 fn default() -> Self {
19 Self {
20 in_batch: false,
21 batch_start: None,
22 }
23 }
24}
25
26fn get_reactivity_state() -> Arc<RwLock<ReactivityState>> {
27 REACTIVITY_STATE.get_or_init(|| Arc::new(RwLock::new(ReactivityState::default()))).clone()
28}
29
30pub fn trigger_realtime_event(file: PathBuf, _content: String) -> Result<()> {
34 tracing::debug!("⚡ Realtime event: {:?}", file);
35
36 Ok(())
40}
41
42pub async fn trigger_debounced_event(file: PathBuf, _content: String) -> Result<()> {
46 tracing::debug!("⏱️ Debounced event: {:?} (300ms)", file);
47
48 sleep(Duration::from_millis(300)).await;
50
51 Ok(())
54}
55
56pub async fn trigger_idle_event(file: PathBuf) -> Result<()> {
60 tracing::debug!("😴 Idle event: {:?} (≥2s idle)", file);
61
62 sleep(Duration::from_secs(2)).await;
64
65 Ok(())
68}
69
70pub fn begin_batch_operation() -> Result<()> {
74 let state = get_reactivity_state();
75 let mut state = state.write();
76
77 tracing::info!("📦 Beginning batch operation");
78 state.in_batch = true;
79 state.batch_start = Some(std::time::Instant::now());
80
81 Ok(())
82}
83
84pub fn end_batch_operation() -> Result<()> {
88 let state = get_reactivity_state();
89 let mut state = state.write();
90
91 if let Some(start) = state.batch_start {
92 let duration = start.elapsed();
93 tracing::info!("✅ Batch operation completed in {:.2}s", duration.as_secs_f64());
94 }
95
96 state.in_batch = false;
97 state.batch_start = None;
98
99 Ok(())
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn test_batch_operation() {
110 begin_batch_operation().unwrap();
111 end_batch_operation().unwrap();
112 }
113
114 #[tokio::test]
115 async fn test_debounced_event() {
116 let file = PathBuf::from("test.ts");
117 let result = trigger_debounced_event(file, "content".to_string()).await;
118 assert!(result.is_ok());
119 }
120}