Created
July 2, 2022 10:35
-
-
Save tripplet/84b4a6b3934c8bb9266031d3852f2aba to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::{ | |
sync::{Arc, Mutex}, | |
thread, | |
}; | |
use crossbeam_channel::{Receiver, Sender}; | |
use log::{debug, error}; | |
use notify::{Error, Event}; | |
use timer::Timer; | |
pub fn debounce_channel( | |
rx: Receiver<Result<Event, Error>>, | |
delay: chrono::Duration, | |
) -> Receiver<Event> { | |
let (tx, rx_debounced) = crossbeam_channel::unbounded(); | |
let tx = Arc::new(tx); | |
thread::spawn(move || debounce_thread(&rx, &tx, delay)); | |
rx_debounced | |
} | |
fn debounce_thread( | |
rx: &Receiver<Result<Event, Error>>, | |
tx: &Arc<Sender<Event>>, | |
delay: chrono::Duration, | |
) { | |
let timer = Timer::new(); | |
let debounced_events = Arc::new(Mutex::new(Vec::with_capacity(10))); | |
for evt in rx.iter() { | |
match evt { | |
Ok(event) => { | |
let event_found = debounced_events.lock().unwrap().iter().any( | |
|(existing_event, _): &(Event, _)| { | |
existing_event.paths == event.paths && existing_event.kind == event.kind | |
}, | |
); | |
if !event_found { | |
// No event in the vec for the given file with the same kind | |
// => Schedule new timer | |
let moved_event = event.clone(); | |
let moved_tx = tx.clone(); | |
let moved_debounced_events = debounced_events.clone(); | |
let guard = timer.schedule_with_delay(delay, move || { | |
// The delay for an event has expired | |
// Get a lock on the vec of debounced events | |
let mut debounced_events_write = moved_debounced_events.lock().unwrap(); | |
// Find the event in the vec | |
let pos = debounced_events_write.iter().position( | |
|(existing_event, _): &(Event, timer::Guard)| { | |
existing_event.paths[0] == moved_event.paths[0] | |
&& existing_event.kind == moved_event.kind | |
}, | |
); | |
// Remove the event from the vec and send it to the debounced channel | |
if let Some(pos) = pos { | |
let (debounced_event, _) = debounced_events_write.swap_remove(pos); | |
moved_tx.send(debounced_event).unwrap(); | |
} | |
}); | |
// Add the event to the debounced events combined with the guard | |
// This keeps the timer alive until the event is removed from the vec | |
debounced_events.lock().unwrap().push((event, guard)); | |
} else { | |
// There is already an event in the vec for the given file with the same kind | |
// We can ignore this new event and wait for the debounce timer to expire | |
debug!("Ignoring event {:?} for {:?}: ", event.kind, event.paths[0]); | |
} | |
} | |
Err(err) => error!("{err:?}"), | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment