-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwatcher.ts
119 lines (103 loc) · 3.15 KB
/
watcher.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import * as fs from 'fs';
import * as path from 'path';
import chokidar, { FSWatcher } from 'chokidar';
import logger from './logger';
import { EventEmitter } from 'events';
export interface WatcherPromise {
onAddDir: (notify: (addedFolderPath: string) => void) => void;
close: () => void;
}
interface WatchPayload {
folderPath: string;
notificationMsg: string;
}
const watcherOptions: chokidar.WatchOptions = {
depth: 0,
persistent: true,
followSymlinks: true,
awaitWriteFinish: true,
useFsEvents: true,
usePolling: true,
interval: 100,
};
export default class Watcher extends EventEmitter {
private parentWatcher?: FSWatcher;
private watcher?: FSWatcher;
private dirs: Array<string> = [];
constructor(
private watchPayload: WatchPayload,
private beforeStart: () => Promise<void>,
private beforeClose: () => Promise<void>,
) {
super();
if (fs.existsSync(this.watchPayload.folderPath)) {
this.dirs = fs.readdirSync(this.watchPayload.folderPath);
}
}
init() {
const self = this;
return new Promise<WatcherPromise>(async (resolve, reject) => {
try {
await this.beforeStart();
logger.info('start watching the folder.');
self.watcher = chokidar.watch(
self.watchPayload.folderPath,
watcherOptions,
);
self.parentWatcher = chokidar.watch(
path.dirname(self.watchPayload.folderPath),
watcherOptions,
);
logger.info('start listening to remove directory event.');
self.onRemove();
self.watcher.on('ready', function onReady() {
logger.info('the folder is successfully watched.');
self.emit('watched');
resolve({
onAddDir: self.onAddDir.bind(self),
close: self.close.bind(self),
});
});
} catch (err) {
this.emit('error', err);
}
});
}
private isValidToNotify(givenPath: string) {
if (path.resolve(this.watchPayload.folderPath) === path.resolve(givenPath))
return false;
const name = path.basename(givenPath);
return !this.dirs.includes(name);
}
private onAddDir(notify: (addedFolderPath: string) => void) {
this.watcher!.on('addDir', (addedFolderPath: string) => {
if (this.isValidToNotify(addedFolderPath)) {
logger.info('new folder is added.', { folderPath: addedFolderPath });
notify(addedFolderPath);
}
});
}
private onRemove() {
this.watcher!.on('unlinkDir', (addedFolderPath: string) => {
const name = path.basename(addedFolderPath);
this.dirs = this.dirs.filter((dir) => dir !== name);
});
this.parentWatcher!.on('unlinkDir', (addedFolderPath: string) => {
if (addedFolderPath === this.watchPayload.folderPath) {
this.close();
}
});
}
private async close() {
logger.info('closing the watcher.');
try {
await this.beforeClose();
await this.watcher!.unwatch(this.watchPayload.folderPath).close();
await this.parentWatcher!.close();
logger.info('the watcher closed successfully.');
this.emit('unwatched');
} catch (error) {
this.emit('error', error);
}
}
}