1+ use anyhow:: { Context , Result } ;
12use notify:: {
2- event:: { MetadataKind , ModifyKind } ,
3+ event:: { AccessKind , AccessMode , MetadataKind , ModifyKind , RenameMode } ,
34 Event , EventKind ,
45} ;
5- use std:: sync:: { atomic:: Ordering :: Relaxed , mpsc:: Sender } ;
6+ use std:: {
7+ sync:: {
8+ atomic:: Ordering :: Relaxed ,
9+ mpsc:: { sync_channel, RecvTimeoutError , Sender , SyncSender } ,
10+ } ,
11+ thread,
12+ time:: Duration ,
13+ } ;
614
715use super :: { WatchEvent , EXERCISE_RUNNING } ;
816
17+ const DEBOUNCE_DURATION : Duration = Duration :: from_millis ( 200 ) ;
18+
919pub struct NotifyEventHandler {
10- pub sender : Sender < WatchEvent > ,
11- /// Used to report which exercise was modified.
12- pub exercise_names : & ' static [ & ' static [ u8 ] ] ,
20+ error_sender : Sender < WatchEvent > ,
21+ // Sends the index of the updated exercise.
22+ update_sender : SyncSender < usize > ,
23+ // Used to report which exercise was modified.
24+ exercise_names : & ' static [ & ' static [ u8 ] ] ,
25+ }
26+
27+ impl NotifyEventHandler {
28+ pub fn build (
29+ watch_event_sender : Sender < WatchEvent > ,
30+ exercise_names : & ' static [ & ' static [ u8 ] ] ,
31+ ) -> Result < Self > {
32+ let ( update_sender, update_receiver) = sync_channel ( 0 ) ;
33+ let error_sender = watch_event_sender. clone ( ) ;
34+
35+ // Debouncer
36+ thread:: Builder :: new ( )
37+ . spawn ( move || {
38+ let mut exercise_updated = vec ! [ false ; exercise_names. len( ) ] ;
39+
40+ loop {
41+ match update_receiver. recv_timeout ( DEBOUNCE_DURATION ) {
42+ Ok ( exercise_ind) => exercise_updated[ exercise_ind] = true ,
43+ Err ( RecvTimeoutError :: Timeout ) => {
44+ for ( exercise_ind, updated) in exercise_updated. iter_mut ( ) . enumerate ( ) {
45+ if * updated {
46+ if watch_event_sender
47+ . send ( WatchEvent :: FileChange { exercise_ind } )
48+ . is_err ( )
49+ {
50+ break ;
51+ }
52+
53+ * updated = false ;
54+ }
55+ }
56+ }
57+ Err ( RecvTimeoutError :: Disconnected ) => break ,
58+ }
59+ }
60+ } )
61+ . context ( "Failed to spawn a thread to debounce file changes" ) ?;
62+
63+ Ok ( Self {
64+ error_sender,
65+ update_sender,
66+ exercise_names,
67+ } )
68+ }
1369}
1470
1571impl notify:: EventHandler for NotifyEventHandler {
@@ -22,8 +78,8 @@ impl notify::EventHandler for NotifyEventHandler {
2278 Ok ( v) => v,
2379 Err ( e) => {
2480 // An error occurs when the receiver is dropped.
25- // After dropping the receiver, the debouncer guard should also be dropped.
26- let _ = self . sender . send ( WatchEvent :: NotifyErr ( e) ) ;
81+ // After dropping the receiver, the watcher guard should also be dropped.
82+ let _ = self . error_sender . send ( WatchEvent :: NotifyErr ( e) ) ;
2783 return ;
2884 }
2985 } ;
@@ -32,6 +88,10 @@ impl notify::EventHandler for NotifyEventHandler {
3288 EventKind :: Any => ( ) ,
3389 EventKind :: Modify ( modify_kind) => match modify_kind {
3490 ModifyKind :: Any | ModifyKind :: Data ( _) => ( ) ,
91+ ModifyKind :: Name ( rename_mode) => match rename_mode {
92+ RenameMode :: Any | RenameMode :: To => ( ) ,
93+ RenameMode :: From | RenameMode :: Both | RenameMode :: Other => return ,
94+ } ,
3595 ModifyKind :: Metadata ( metadata_kind) => match metadata_kind {
3696 MetadataKind :: Any | MetadataKind :: WriteTime => ( ) ,
3797 MetadataKind :: AccessTime
@@ -40,12 +100,17 @@ impl notify::EventHandler for NotifyEventHandler {
40100 | MetadataKind :: Extended
41101 | MetadataKind :: Other => return ,
42102 } ,
43- ModifyKind :: Name ( _) | ModifyKind :: Other => return ,
103+ ModifyKind :: Other => return ,
104+ } ,
105+ EventKind :: Access ( access_kind) => match access_kind {
106+ AccessKind :: Any => ( ) ,
107+ AccessKind :: Close ( access_mode) => match access_mode {
108+ AccessMode :: Any | AccessMode :: Write => ( ) ,
109+ AccessMode :: Execute | AccessMode :: Read | AccessMode :: Other => return ,
110+ } ,
111+ AccessKind :: Read | AccessKind :: Open ( _) | AccessKind :: Other => return ,
44112 } ,
45- EventKind :: Access ( _)
46- | EventKind :: Create ( _)
47- | EventKind :: Remove ( _)
48- | EventKind :: Other => return ,
113+ EventKind :: Create ( _) | EventKind :: Remove ( _) | EventKind :: Other => return ,
49114 }
50115
51116 let _ = input_event
@@ -62,6 +127,6 @@ impl notify::EventHandler for NotifyEventHandler {
62127 . iter ( )
63128 . position ( |exercise_name| * exercise_name == file_name_without_ext)
64129 } )
65- . try_for_each ( |exercise_ind| self . sender . send ( WatchEvent :: FileChange { exercise_ind } ) ) ;
130+ . try_for_each ( |exercise_ind| self . update_sender . send ( exercise_ind) ) ;
66131 }
67132}
0 commit comments