Skip to content

Commit f62d21c

Browse files
author
Benjamin Pasero
committed
debt - adopt IPC utilities for nsfw watcher service
1 parent ec415d5 commit f62d21c

5 files changed

Lines changed: 83 additions & 148 deletions

File tree

src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts

Lines changed: 69 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ import * as path from 'vs/base/common/path';
99
import * as platform from 'vs/base/common/platform';
1010
import { IDiskFileChange, normalizeFileChanges, ILogMessage } from 'vs/platform/files/node/watcher/watcher';
1111
import * as nsfw from 'vscode-nsfw';
12-
import { IWatcherService, IWatcherRequest, IWatcherOptions } from 'vs/platform/files/node/watcher/nsfw/watcher';
12+
import { IWatcherService, IWatcherRequest } from 'vs/platform/files/node/watcher/nsfw/watcher';
1313
import { ThrottledDelayer } from 'vs/base/common/async';
1414
import { FileChangeType } from 'vs/platform/files/common/files';
1515
import { normalizeNFC } from 'vs/base/common/normalization';
1616
import { Event, Emitter } from 'vs/base/common/event';
1717
import { realcaseSync, realpathSync } from 'vs/base/node/extpath';
18+
import { Disposable } from 'vs/base/common/lifecycle';
1819

1920
const nsfwActionToRawChangeType: { [key: number]: number } = [];
2021
nsfwActionToRawChangeType[nsfw.actions.CREATED] = FileChangeType.ADDED;
@@ -32,29 +33,61 @@ interface IPathWatcher {
3233
ignored: glob.ParsedPattern[];
3334
}
3435

35-
export class NsfwWatcherService implements IWatcherService {
36+
export class NsfwWatcherService extends Disposable implements IWatcherService {
37+
3638
private static readonly FS_EVENT_DELAY = 50; // aggregate and only emit events when changes have stopped for this duration (in ms)
3739

38-
private _pathWatchers: { [watchPath: string]: IPathWatcher } = {};
39-
private _verboseLogging: boolean | undefined;
40+
private readonly _onDidChangeFile = this._register(new Emitter<IDiskFileChange[]>());
41+
readonly onDidChangeFile = this._onDidChangeFile.event;
42+
43+
private readonly _onDidLogMessage = this._register(new Emitter<ILogMessage>());
44+
readonly onDidLogMessage: Event<ILogMessage> = this._onDidLogMessage.event;
45+
46+
private pathWatchers: { [watchPath: string]: IPathWatcher } = {};
47+
private verboseLogging: boolean | undefined;
4048
private enospcErrorLogged: boolean | undefined;
4149

42-
private readonly _onWatchEvent = new Emitter<IDiskFileChange[]>();
43-
readonly onWatchEvent = this._onWatchEvent.event;
50+
async setRoots(roots: IWatcherRequest[]): Promise<void> {
51+
const normalizedRoots = this._normalizeRoots(roots);
52+
53+
// Gather roots that are not currently being watched
54+
const rootsToStartWatching = normalizedRoots.filter(r => {
55+
return !(r.path in this.pathWatchers);
56+
});
57+
58+
// Gather current roots that don't exist in the new roots array
59+
const rootsToStopWatching = Object.keys(this.pathWatchers).filter(r => {
60+
return normalizedRoots.every(normalizedRoot => normalizedRoot.path !== r);
61+
});
62+
63+
// Logging
64+
if (this.verboseLogging) {
65+
this.log(`Start watching: [${rootsToStartWatching.map(r => r.path).join(',')}]\nStop watching: [${rootsToStopWatching.join(',')}]`);
66+
}
67+
68+
// Stop watching some roots
69+
rootsToStopWatching.forEach(root => {
70+
this.pathWatchers[root].ready.then(watcher => watcher.stop());
71+
delete this.pathWatchers[root];
72+
});
4473

45-
private readonly _onLogMessage = new Emitter<ILogMessage>();
46-
readonly onLogMessage: Event<ILogMessage> = this._onLogMessage.event;
74+
// Start watching some roots
75+
rootsToStartWatching.forEach(root => this.doWatch(root));
4776

48-
watch(options: IWatcherOptions): Event<IDiskFileChange[]> {
49-
return this.onWatchEvent;
77+
// Refresh ignored arrays in case they changed
78+
roots.forEach(root => {
79+
if (root.path in this.pathWatchers) {
80+
this.pathWatchers[root.path].ignored = Array.isArray(root.excludes) ? root.excludes.map(ignored => glob.parse(ignored)) : [];
81+
}
82+
});
5083
}
5184

52-
private _watch(request: IWatcherRequest): void {
85+
private doWatch(request: IWatcherRequest): void {
5386
let undeliveredFileEvents: IDiskFileChange[] = [];
5487
const fileEventDelayer = new ThrottledDelayer<void>(NsfwWatcherService.FS_EVENT_DELAY);
5588

5689
let readyPromiseResolve: (watcher: IWatcherObjet) => void;
57-
this._pathWatchers[request.path] = {
90+
this.pathWatchers[request.path] = {
5891
ready: new Promise<IWatcherObjet>(resolve => readyPromiseResolve = resolve),
5992
ignored: Array.isArray(request.excludes) ? request.excludes.map(ignored => glob.parse(ignored)) : []
6093
};
@@ -100,14 +133,14 @@ export class NsfwWatcherService implements IWatcherService {
100133
}
101134
}
102135

103-
if (this._verboseLogging) {
136+
if (this.verboseLogging) {
104137
this.log(`Start watching with nsfw: ${request.path}`);
105138
}
106139

107140
nsfw(request.path, events => {
108141
for (const e of events) {
109142
// Logging
110-
if (this._verboseLogging) {
143+
if (this.verboseLogging) {
111144
const logPath = e.action === nsfw.actions.RENAMED ? path.join(e.directory, e.oldFile || '') + ' -> ' + e.newFile : path.join(e.directory, e.file || '');
112145
this.log(`${e.action === nsfw.actions.CREATED ? '[CREATED]' : e.action === nsfw.actions.DELETED ? '[DELETED]' : e.action === nsfw.actions.MODIFIED ? '[CHANGED]' : '[RENAMED]'} ${logPath}`);
113146
}
@@ -117,25 +150,25 @@ export class NsfwWatcherService implements IWatcherService {
117150
if (e.action === nsfw.actions.RENAMED) {
118151
// Rename fires when a file's name changes within a single directory
119152
absolutePath = path.join(e.directory, e.oldFile || '');
120-
if (!this._isPathIgnored(absolutePath, this._pathWatchers[request.path].ignored)) {
153+
if (!this.isPathIgnored(absolutePath, this.pathWatchers[request.path].ignored)) {
121154
undeliveredFileEvents.push({ type: FileChangeType.DELETED, path: absolutePath });
122-
} else if (this._verboseLogging) {
155+
} else if (this.verboseLogging) {
123156
this.log(` >> ignored ${absolutePath}`);
124157
}
125158
absolutePath = path.join(e.newDirectory || e.directory, e.newFile || '');
126-
if (!this._isPathIgnored(absolutePath, this._pathWatchers[request.path].ignored)) {
159+
if (!this.isPathIgnored(absolutePath, this.pathWatchers[request.path].ignored)) {
127160
undeliveredFileEvents.push({ type: FileChangeType.ADDED, path: absolutePath });
128-
} else if (this._verboseLogging) {
161+
} else if (this.verboseLogging) {
129162
this.log(` >> ignored ${absolutePath}`);
130163
}
131164
} else {
132165
absolutePath = path.join(e.directory, e.file || '');
133-
if (!this._isPathIgnored(absolutePath, this._pathWatchers[request.path].ignored)) {
166+
if (!this.isPathIgnored(absolutePath, this.pathWatchers[request.path].ignored)) {
134167
undeliveredFileEvents.push({
135168
type: nsfwActionToRawChangeType[e.action],
136169
path: absolutePath
137170
});
138-
} else if (this._verboseLogging) {
171+
} else if (this.verboseLogging) {
139172
this.log(` >> ignored ${absolutePath}`);
140173
}
141174
}
@@ -161,94 +194,59 @@ export class NsfwWatcherService implements IWatcherService {
161194

162195
// Broadcast to clients normalized
163196
const res = normalizeFileChanges(events);
164-
this._onWatchEvent.fire(res);
197+
this._onDidChangeFile.fire(res);
165198

166199
// Logging
167-
if (this._verboseLogging) {
200+
if (this.verboseLogging) {
168201
res.forEach(r => {
169202
this.log(` >> normalized ${r.type === FileChangeType.ADDED ? '[ADDED]' : r.type === FileChangeType.DELETED ? '[DELETED]' : '[CHANGED]'} ${r.path}`);
170203
});
171204
}
172205
});
173206
}).then(watcher => {
174-
this._pathWatchers[request.path].watcher = watcher;
207+
this.pathWatchers[request.path].watcher = watcher;
175208
const startPromise = watcher.start();
176209
startPromise.then(() => readyPromiseResolve(watcher));
177-
return startPromise;
178-
});
179-
}
180-
181-
async setRoots(roots: IWatcherRequest[]): Promise<void> {
182-
const normalizedRoots = this._normalizeRoots(roots);
183-
184-
// Gather roots that are not currently being watched
185-
const rootsToStartWatching = normalizedRoots.filter(r => {
186-
return !(r.path in this._pathWatchers);
187-
});
188210

189-
// Gather current roots that don't exist in the new roots array
190-
const rootsToStopWatching = Object.keys(this._pathWatchers).filter(r => {
191-
return normalizedRoots.every(normalizedRoot => normalizedRoot.path !== r);
192-
});
193-
194-
// Logging
195-
if (this._verboseLogging) {
196-
this.log(`Start watching: [${rootsToStartWatching.map(r => r.path).join(',')}]\nStop watching: [${rootsToStopWatching.join(',')}]`);
197-
}
198-
199-
// Stop watching some roots
200-
rootsToStopWatching.forEach(root => {
201-
this._pathWatchers[root].ready.then(watcher => watcher.stop());
202-
delete this._pathWatchers[root];
203-
});
204-
205-
// Start watching some roots
206-
rootsToStartWatching.forEach(root => this._watch(root));
207-
208-
// Refresh ignored arrays in case they changed
209-
roots.forEach(root => {
210-
if (root.path in this._pathWatchers) {
211-
this._pathWatchers[root.path].ignored = Array.isArray(root.excludes) ? root.excludes.map(ignored => glob.parse(ignored)) : [];
212-
}
211+
return startPromise;
213212
});
214213
}
215214

216215
async setVerboseLogging(enabled: boolean): Promise<void> {
217-
this._verboseLogging = enabled;
216+
this.verboseLogging = enabled;
218217
}
219218

220219
async stop(): Promise<void> {
221-
for (let path in this._pathWatchers) {
222-
let watcher = this._pathWatchers[path];
220+
for (let path in this.pathWatchers) {
221+
let watcher = this.pathWatchers[path];
223222
watcher.ready.then(watcher => watcher.stop());
224-
delete this._pathWatchers[path];
223+
delete this.pathWatchers[path];
225224
}
226-
this._pathWatchers = Object.create(null);
225+
226+
this.pathWatchers = Object.create(null);
227227
}
228228

229-
/**
230-
* Normalizes a set of root paths by removing any root paths that are
231-
* sub-paths of other roots.
232-
*/
233229
protected _normalizeRoots(roots: IWatcherRequest[]): IWatcherRequest[] {
230+
// Normalizes a set of root paths by removing any root paths that are
231+
// sub-paths of other roots.
234232
return roots.filter(r => roots.every(other => {
235233
return !(r.path.length > other.path.length && extpath.isEqualOrParent(r.path, other.path));
236234
}));
237235
}
238236

239-
private _isPathIgnored(absolutePath: string, ignored: glob.ParsedPattern[]): boolean {
237+
private isPathIgnored(absolutePath: string, ignored: glob.ParsedPattern[]): boolean {
240238
return ignored && ignored.some(i => i(absolutePath));
241239
}
242240

243241
private log(message: string) {
244-
this._onLogMessage.fire({ type: 'trace', message: `[File Watcher (nsfw)] ` + message });
242+
this._onDidLogMessage.fire({ type: 'trace', message: `[File Watcher (nsfw)] ` + message });
245243
}
246244

247245
private warn(message: string) {
248-
this._onLogMessage.fire({ type: 'warn', message: `[File Watcher (nsfw)] ` + message });
246+
this._onDidLogMessage.fire({ type: 'warn', message: `[File Watcher (nsfw)] ` + message });
249247
}
250248

251249
private error(message: string) {
252-
this._onLogMessage.fire({ type: 'error', message: `[File Watcher (nsfw)] ` + message });
250+
this._onDidLogMessage.fire({ type: 'error', message: `[File Watcher (nsfw)] ` + message });
253251
}
254252
}

src/vs/platform/files/node/watcher/nsfw/watcher.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ export interface IWatcherRequest {
1111
excludes: string[];
1212
}
1313

14-
export interface IWatcherOptions {
15-
}
16-
1714
export interface IWatcherService {
18-
watch(options: IWatcherOptions): Event<IDiskFileChange[]>;
15+
16+
readonly onDidLogMessage: Event<ILogMessage>;
17+
readonly onDidChangeFile: Event<IDiskFileChange[]>;
18+
1919
setRoots(roots: IWatcherRequest[]): Promise<void>;
2020
setVerboseLogging(enabled: boolean): Promise<void>;
21-
onLogMessage: Event<ILogMessage>;
21+
2222
stop(): Promise<void>;
23-
}
23+
}

src/vs/platform/files/node/watcher/nsfw/watcherApp.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { Server } from 'vs/base/parts/ipc/node/ipc.cp';
7-
import { WatcherChannel } from 'vs/platform/files/node/watcher/nsfw/watcherIpc';
87
import { NsfwWatcherService } from 'vs/platform/files/node/watcher/nsfw/nsfwWatcherService';
8+
import { createChannelReceiver } from 'vs/base/parts/ipc/common/ipc';
99

1010
const server = new Server('watcher');
1111
const service = new NsfwWatcherService();
12-
const channel = new WatcherChannel(service);
13-
server.registerChannel('watcher', channel);
12+
server.registerChannel('watcher', createChannelReceiver(service));

src/vs/platform/files/node/watcher/nsfw/watcherIpc.ts

Lines changed: 0 additions & 58 deletions
This file was deleted.

src/vs/platform/files/node/watcher/nsfw/watcherService.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,18 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { getNextTickChannel } from 'vs/base/parts/ipc/common/ipc';
6+
import { createChannelSender, getNextTickChannel } from 'vs/base/parts/ipc/common/ipc';
77
import { Client } from 'vs/base/parts/ipc/node/ipc.cp';
88
import { IDiskFileChange, ILogMessage } from 'vs/platform/files/node/watcher/watcher';
9-
import { WatcherChannelClient } from 'vs/platform/files/node/watcher/nsfw/watcherIpc';
109
import { Disposable } from 'vs/base/common/lifecycle';
11-
import { IWatcherRequest } from 'vs/platform/files/node/watcher/nsfw/watcher';
10+
import { IWatcherRequest, IWatcherService } from 'vs/platform/files/node/watcher/nsfw/watcher';
1211
import { getPathFromAmdModule } from 'vs/base/common/amd';
1312

1413
export class FileWatcher extends Disposable {
1514

1615
private static readonly MAX_RESTARTS = 5;
1716

18-
private service: WatcherChannelClient | undefined;
17+
private service: IWatcherService | undefined;
1918
private isDisposed: boolean;
2019
private restartCounter: number;
2120

@@ -62,15 +61,12 @@ export class FileWatcher extends Disposable {
6261
}));
6362

6463
// Initialize watcher
65-
const channel = getNextTickChannel(client.getChannel('watcher'));
66-
this.service = new WatcherChannelClient(channel);
64+
this.service = createChannelSender<IWatcherService>(getNextTickChannel(client.getChannel('watcher')));
6765

6866
this.service.setVerboseLogging(this.verboseLogging);
6967

70-
const options = {};
71-
this._register(this.service.watch(options)(e => !this.isDisposed && this.onDidFilesChange(e)));
72-
73-
this._register(this.service.onLogMessage(m => this.onLogMessage(m)));
68+
this._register(this.service.onDidChangeFile(e => !this.isDisposed && this.onDidFilesChange(e)));
69+
this._register(this.service.onDidLogMessage(m => this.onLogMessage(m)));
7470

7571
// Start watching
7672
this.setFolders(this.folders);

0 commit comments

Comments
 (0)