4
4
*/
5
5
6
6
/*
7
- Watch a file for changes
7
+ Watch one SINGLE FILE for changes. Use ./path-watcher.ts for a directory.
8
8
9
9
Watch for changes to the given file. Returns obj, which
10
10
is an event emitter with events:
11
11
12
- - 'change', ctime - when file changes or is created
12
+ - 'change', ctime, stats - when file changes or is created
13
13
- 'delete' - when file is deleted
14
14
15
15
and a method .close().
@@ -25,30 +25,30 @@ import { watch, FSWatcher } from "chokidar";
25
25
import { getLogger } from "./logger" ;
26
26
import { debounce as lodashDebounce } from "lodash" ;
27
27
28
- const L = getLogger ( "watcher" ) ;
28
+ const logger = getLogger ( "backend: watcher" ) ;
29
29
30
30
export class Watcher extends EventEmitter {
31
31
private path : string ;
32
- private interval : number ;
33
32
private watcher : FSWatcher ;
34
33
35
- constructor ( path : string , interval : number = 300 , debounce : number = 0 ) {
34
+ constructor (
35
+ path : string ,
36
+ { debounce, interval = 300 } : { debounce ?: number ; interval ?: number } = { } ,
37
+ ) {
36
38
super ( ) ;
37
39
this . path = path ;
38
- this . interval = interval ;
39
40
40
- L . debug ( ` ${ path } : interval= ${ interval } , debounce= ${ debounce } ` ) ;
41
+ logger . debug ( { path , debounce, interval } ) ;
41
42
this . watcher = watch ( this . path , {
42
- interval : this . interval ,
43
+ interval,
43
44
// polling is critical for network mounted file systems,
44
45
// and given architecture of cocalc there is no easy way around this.
45
46
// E.g., on compute servers, everything breaks involving sync or cloudfs,
46
47
// and in shared project s3/gcsfuse/sshfs would all break. So we
47
48
// use polling.
48
49
usePolling : true ,
49
- persistent : false ,
50
+ persistent : true ,
50
51
alwaysStat : true ,
51
- atomic : true ,
52
52
} ) ;
53
53
this . watcher . on ( "unlink" , ( ) => {
54
54
this . emit ( "delete" ) ;
@@ -57,24 +57,29 @@ export class Watcher extends EventEmitter {
57
57
this . emit ( "delete" ) ;
58
58
} ) ;
59
59
60
- const emitChange = lodashDebounce (
61
- ( ctime ) => this . emit ( "change" , ctime ) ,
62
- debounce ,
63
- ) ;
60
+ const f = ( ctime , stats ) => {
61
+ logger . debug ( "change" , this . path , ctime ) ;
62
+ this . emit ( "change" , ctime , stats ) ;
63
+ } ;
64
+ const emitChange = debounce ? lodashDebounce ( f , debounce ) : f ;
65
+
64
66
this . watcher . on ( "error" , ( err ) => {
65
- L . debug ( "WATCHER error -- " , err ) ;
67
+ logger . debug ( "WATCHER error -- " , err ) ;
66
68
} ) ;
67
69
68
70
this . watcher . on ( "change" , ( _ , stats ) => {
69
71
if ( stats == null ) {
70
- L . debug ( "WATCHER change with no stats (shouldn't happen)" , { path } ) ;
72
+ logger . debug ( "WATCHER change with no stats (shouldn't happen)" , {
73
+ path,
74
+ } ) ;
71
75
return ;
72
76
}
73
- emitChange ( stats . ctime ) ;
77
+ emitChange ( stats . ctime , stats ) ;
74
78
} ) ;
75
79
}
76
80
77
81
close = async ( ) => {
82
+ logger . debug ( "close" , this . path ) ;
78
83
this . removeAllListeners ( ) ;
79
84
await this . watcher . close ( ) ;
80
85
} ;
0 commit comments