1
+ use anyhow:: { Context , Result } ;
1
2
use notify:: {
2
- event:: { MetadataKind , ModifyKind } ,
3
+ event:: { AccessKind , AccessMode , MetadataKind , ModifyKind , RenameMode } ,
3
4
Event , EventKind ,
4
5
} ;
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
+ } ;
6
14
7
15
use super :: { WatchEvent , EXERCISE_RUNNING } ;
8
16
17
+ const DEBOUNCE_DURATION : Duration = Duration :: from_millis ( 200 ) ;
18
+
9
19
pub 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
+ }
13
69
}
14
70
15
71
impl notify:: EventHandler for NotifyEventHandler {
@@ -22,8 +78,8 @@ impl notify::EventHandler for NotifyEventHandler {
22
78
Ok ( v) => v,
23
79
Err ( e) => {
24
80
// 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) ) ;
27
83
return ;
28
84
}
29
85
} ;
@@ -32,6 +88,10 @@ impl notify::EventHandler for NotifyEventHandler {
32
88
EventKind :: Any => ( ) ,
33
89
EventKind :: Modify ( modify_kind) => match modify_kind {
34
90
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
+ } ,
35
95
ModifyKind :: Metadata ( metadata_kind) => match metadata_kind {
36
96
MetadataKind :: Any | MetadataKind :: WriteTime => ( ) ,
37
97
MetadataKind :: AccessTime
@@ -40,12 +100,17 @@ impl notify::EventHandler for NotifyEventHandler {
40
100
| MetadataKind :: Extended
41
101
| MetadataKind :: Other => return ,
42
102
} ,
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 ,
44
112
} ,
45
- EventKind :: Access ( _)
46
- | EventKind :: Create ( _)
47
- | EventKind :: Remove ( _)
48
- | EventKind :: Other => return ,
113
+ EventKind :: Create ( _) | EventKind :: Remove ( _) | EventKind :: Other => return ,
49
114
}
50
115
51
116
let _ = input_event
@@ -62,6 +127,6 @@ impl notify::EventHandler for NotifyEventHandler {
62
127
. iter ( )
63
128
. position ( |exercise_name| * exercise_name == file_name_without_ext)
64
129
} )
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) ) ;
66
131
}
67
132
}
0 commit comments