Skip to content

Commit c8532d7

Browse files
committed
fix: watcher id
1 parent 56a3176 commit c8532d7

7 files changed

Lines changed: 85 additions & 106 deletions

File tree

packages/file-service/src/node/data-store/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,3 @@ export interface WatchInsData {
77

88
disposable: RefCountedDisposable;
99
}
10-
11-
export const fileChangeEvent = (watcherId: number | string) => `file-changes-${watcherId}`;

packages/file-service/src/node/disk-file-system.provider.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { Autowired, INJECTOR_TOKEN, Injectable, Injector, Optional } from '@open
1010
import { RPCService } from '@opensumi/ide-connection';
1111
import {
1212
Deferred,
13-
DisposableCollection,
1413
Emitter,
1514
Event,
1615
FileUri,
@@ -45,7 +44,8 @@ import {
4544
notEmpty,
4645
} from '../common/';
4746

48-
import { WatchInsData, fileChangeEvent } from './data-store';
47+
import { WatchInsData } from './data-store';
48+
import { FileChangeCollectionManager } from './file-change-collection';
4949
import { FileSystemWatcherServer } from './recursive/file-service-watcher';
5050
import { getFileType } from './shared/file-type';
5151
import { UnRecursiveFileSystemWatcher } from './un-recursive/file-service-watcher';
@@ -89,6 +89,9 @@ export class DiskFileSystemProvider extends RPCService<IRPCDiskFileSystemProvide
8989
@GDataStore(WatchInsData, { id: 'watcherId' })
9090
private watcherGDataStore: GDataStore<WatchInsData, 'watcherId'>;
9191

92+
@Autowired(FileChangeCollectionManager)
93+
private readonly fileChangeCollectionManager: FileChangeCollectionManager;
94+
9295
private logger: ILogService;
9396

9497
private ignoreNextChangesEvent: Set<string> = new Set();
@@ -141,8 +144,8 @@ export class DiskFileSystemProvider extends RPCService<IRPCDiskFileSystemProvide
141144
excludes: options?.excludes ?? [],
142145
});
143146

144-
const listenHandle = this.watcherGDataStore.on(fileChangeEvent(id), (data) => {
145-
this.handleFileChanges(data);
147+
const listenHandle = this.fileChangeCollectionManager.onFileChange(id, (changes) => {
148+
this.handleFileChanges(changes);
146149
});
147150

148151
const disposable = {

packages/file-service/src/node/file-change-collection.ts

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616

1717
// Some code copied and modified from https://github.com/eclipse-theia/theia/tree/v1.14.0/packages/filesystem/src/node/file-change-collection.ts
1818

19-
import groupBy from 'lodash/groupBy';
19+
import debounce from 'lodash/debounce';
20+
21+
import { Injectable } from '@opensumi/di';
22+
import { DefaultMap, Dispatcher, FileUri } from '@opensumi/ide-utils';
2023

2124
import { FileChange, FileChangeType } from '../common';
2225

@@ -71,11 +74,49 @@ export class FileChangeCollection {
7174
return Array.from(this.changes.values());
7275
}
7376

74-
groupByWatcherId(): Record<string, FileChange[]> {
75-
return groupBy(this.values(), 'watcherId');
76-
}
77-
7877
reset(): void {
7978
this.changes.clear();
8079
}
8180
}
81+
82+
@Injectable()
83+
export class FileChangeCollectionManager {
84+
private _onFileChangeEmitter = new Dispatcher<FileChange[]>();
85+
public readonly onFileChange = (watcherId: number, cb: (change: FileChange[]) => void) =>
86+
this._onFileChangeEmitter.on(String(watcherId))(cb);
87+
88+
protected changes = new DefaultMap<number, FileChangeCollection>(() => new FileChangeCollection());
89+
90+
/**
91+
* Fires file changes to clients.
92+
* It is debounced in the case if the filesystem is spamming to avoid overwhelming clients with events.
93+
*/
94+
protected readonly fireDidFilesChanged: () => void = debounce(() => this.doFireDidFilesChanged(), 100);
95+
protected doFireDidFilesChanged(): void {
96+
this.changes.forEach((change, watcherId) => {
97+
const data = change.values();
98+
change.reset();
99+
100+
this._onFileChangeEmitter.dispatch(String(watcherId), data);
101+
});
102+
}
103+
104+
pushAdded(watcherId: number, path: string): void {
105+
this.pushFileChange(watcherId, path, FileChangeType.ADDED);
106+
}
107+
108+
pushUpdated(watcherId: number, path: string): void {
109+
this.pushFileChange(watcherId, path, FileChangeType.UPDATED);
110+
}
111+
112+
pushDeleted(watcherId: number, path: string): void {
113+
this.pushFileChange(watcherId, path, FileChangeType.DELETED);
114+
}
115+
116+
protected pushFileChange(watcherId: number, path: string, type: FileChangeType): void {
117+
const uri = FileUri.create(path).toString();
118+
this.changes.get(watcherId).push({ uri, type });
119+
120+
this.fireDidFilesChanged();
121+
}
122+
}

packages/file-service/src/node/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { FileServicePath, FileSystemProvider, IDiskFileProvider, IFileService }
55

66
import { DiskFileSystemProvider } from './disk-file-system.provider';
77
import { DiskFileRemoteService } from './disk-file.remote-service';
8+
import { FileChangeCollectionManager } from './file-change-collection';
89
import { getSafeFileservice } from './file-service';
910

1011
export * from './file-service';
@@ -24,6 +25,11 @@ export class FileServiceModule extends NodeModule {
2425
providers = [
2526
{ token: IFileService, useFactory: (injector: Injector) => getSafeFileservice(injector) },
2627
{ token: IDiskFileProvider, useFactory: (injector: Injector) => getFileservice(injector, DiskFileSystemProvider) },
28+
// 单例 FileChangeCollectionManager
29+
{
30+
token: FileChangeCollectionManager,
31+
useClass: FileChangeCollectionManager,
32+
},
2733
];
2834

2935
remoteServices = [DiskFileRemoteService];

packages/file-service/src/node/recursive/file-service-watcher.ts

Lines changed: 15 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ import paths from 'path';
22

33
import ParcelWatcher from '@parcel/watcher';
44
import fs from 'fs-extra';
5-
import debounce from 'lodash/debounce';
65
import uniqBy from 'lodash/uniqBy';
76

87
import { Autowired, Injectable, Optional } from '@opensumi/di';
98
import {
10-
DefaultMap,
119
Disposable,
1210
DisposableCollection,
1311
FileUri,
@@ -24,9 +22,9 @@ import {
2422
sleep,
2523
} from '@opensumi/ide-core-node';
2624

27-
import { FileChangeType, FileSystemWatcherClient, IFileSystemWatcherServer, INsfw, WatchOptions } from '../../common';
28-
import { WatchInsData, fileChangeEvent } from '../data-store';
29-
import { FileChangeCollection } from '../file-change-collection';
25+
import { FileSystemWatcherClient, IFileSystemWatcherServer, INsfw, WatchOptions } from '../../common';
26+
import { WatchInsData } from '../data-store';
27+
import { FileChangeCollectionManager } from '../file-change-collection';
3028
import { shouldIgnorePath } from '../shared';
3129

3230
export interface WatcherOptions {
@@ -50,14 +48,15 @@ export class FileSystemWatcherServer extends Disposable implements IFileSystemWa
5048
private static WATCHER_SEQUENCE = 1;
5149
protected watcherOptions = new Map<number, WatcherOptions>();
5250

53-
protected changes = new DefaultMap<number, FileChangeCollection>(() => new FileChangeCollection());
54-
5551
@Autowired(ILogServiceManager)
5652
private readonly loggerManager: ILogServiceManager;
5753

5854
@GDataStore(WatchInsData, { id: 'watcherId' })
5955
private watcherGDataStore: GDataStore<WatchInsData, 'watcherId'>;
6056

57+
@Autowired(FileChangeCollectionManager)
58+
private readonly fileChangeCollectionManager: FileChangeCollectionManager;
59+
6160
private logger: ILogService;
6261

6362
constructor(@Optional() private readonly excludes: string[] = []) {
@@ -201,13 +200,13 @@ export class FileSystemWatcherServer extends Disposable implements IFileSystemWa
201200
for (const event of events) {
202201
switch (event.type) {
203202
case 'create':
204-
this.pushAdded(watcherId, event.path);
203+
this.fileChangeCollectionManager.pushAdded(watcherId, event.path);
205204
break;
206205
case 'delete':
207-
this.pushDeleted(watcherId, event.path);
206+
this.fileChangeCollectionManager.pushDeleted(watcherId, event.path);
208207
break;
209208
case 'update':
210-
this.pushUpdated(watcherId, event.path);
209+
this.fileChangeCollectionManager.pushUpdated(watcherId, event.path);
211210
break;
212211
}
213212
}
@@ -361,22 +360,22 @@ export class FileSystemWatcherServer extends Disposable implements IFileSystemWa
361360
return;
362361
}
363362

364-
this.pushDeleted(watcherId, deletedPath);
363+
this.fileChangeCollectionManager.pushDeleted(watcherId, deletedPath);
365364

366365
if (event.newDirectory) {
367366
const path = await this.resolvePath(event.newDirectory, event.newFile!);
368367
if (isIgnored(watcherId, path)) {
369368
return;
370369
}
371370

372-
this.pushAdded(watcherId, path);
371+
this.fileChangeCollectionManager.pushAdded(watcherId, path);
373372
} else {
374373
const path = await this.resolvePath(event.directory, event.newFile!);
375374
if (isIgnored(watcherId, path)) {
376375
return;
377376
}
378377

379-
this.pushAdded(watcherId, path);
378+
this.fileChangeCollectionManager.pushAdded(watcherId, path);
380379
}
381380
}
382381
break;
@@ -389,13 +388,13 @@ export class FileSystemWatcherServer extends Disposable implements IFileSystemWa
389388

390389
switch (event.action) {
391390
case INsfw.actions.CREATED:
392-
this.pushAdded(watcherId, path);
391+
this.fileChangeCollectionManager.pushAdded(watcherId, path);
393392
break;
394393
case INsfw.actions.DELETED:
395-
this.pushDeleted(watcherId, path);
394+
this.fileChangeCollectionManager.pushDeleted(watcherId, path);
396395
break;
397396
case INsfw.actions.MODIFIED:
398-
this.pushUpdated(watcherId, path);
397+
this.fileChangeCollectionManager.pushUpdated(watcherId, path);
399398
break;
400399
}
401400
}
@@ -405,25 +404,6 @@ export class FileSystemWatcherServer extends Disposable implements IFileSystemWa
405404
);
406405
}
407406

408-
protected pushAdded(watcherId: number, path: string): void {
409-
this.pushFileChange(watcherId, path, FileChangeType.ADDED);
410-
}
411-
412-
protected pushUpdated(watcherId: number, path: string): void {
413-
this.pushFileChange(watcherId, path, FileChangeType.UPDATED);
414-
}
415-
416-
protected pushDeleted(watcherId: number, path: string): void {
417-
this.pushFileChange(watcherId, path, FileChangeType.DELETED);
418-
}
419-
420-
protected pushFileChange(watcherId: number, path: string, type: FileChangeType): void {
421-
const uri = FileUri.create(path).toString();
422-
this.changes.get(watcherId).push({ uri, type });
423-
424-
this.fireDidFilesChanged();
425-
}
426-
427407
protected async resolvePath(directory: string, file: string): Promise<string> {
428408
const path = paths.join(directory, file);
429409
// 如果是 linux 则获取一下真实 path,以防返回的是软连路径被过滤
@@ -442,18 +422,6 @@ export class FileSystemWatcherServer extends Disposable implements IFileSystemWa
442422
}
443423
return path;
444424
}
445-
446-
/**
447-
* Fires file changes to clients.
448-
* It is debounced in the case if the filesystem is spamming to avoid overwhelming clients with events.
449-
*/
450-
protected readonly fireDidFilesChanged: () => void = debounce(() => this.doFireDidFilesChanged(), 100);
451-
protected doFireDidFilesChanged(): void {
452-
this.changes.forEach((change, watcherId) => {
453-
const data = change.values();
454-
this.watcherGDataStore.emit(fileChangeEvent(watcherId), data);
455-
});
456-
}
457425
}
458426

459427
function requireNSFWModule(): typeof import('nsfw') {

packages/file-service/src/node/un-recursive/file-service-watcher.ts

Lines changed: 10 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import fs, { watch } from 'fs-extra';
2-
import debounce from 'lodash/debounce';
3-
import groupBy from 'lodash/groupBy';
42

53
import { Autowired, Injectable, Optional } from '@opensumi/di';
64
import {
7-
DefaultMap,
85
Disposable,
96
DisposableCollection,
107
FileUri,
@@ -18,9 +15,9 @@ import {
1815
sleep,
1916
} from '@opensumi/ide-core-node';
2017

21-
import { FileChangeType, IFileSystemWatcherServer } from '../../common/index';
22-
import { WatchInsData, fileChangeEvent } from '../data-store';
23-
import { FileChangeCollection } from '../file-change-collection';
18+
import { IFileSystemWatcherServer } from '../../common/index';
19+
import { WatchInsData } from '../data-store';
20+
import { FileChangeCollectionManager } from '../file-change-collection';
2421
import { shouldIgnorePath } from '../shared';
2522

2623
const { join, basename, normalize } = path;
@@ -45,8 +42,8 @@ export class UnRecursiveFileSystemWatcher extends Disposable implements IFileSys
4542
@GDataStore(WatchInsData, { id: 'watcherId' })
4643
private watcherGDataStore: GDataStore<WatchInsData, 'watcherId'>;
4744

48-
// 收集发生改变的文件
49-
protected changes = new DefaultMap<number, FileChangeCollection>(() => new FileChangeCollection());
45+
@Autowired(FileChangeCollectionManager)
46+
private readonly fileChangeCollectionManager: FileChangeCollectionManager;
5047

5148
private logger: ILogService;
5249

@@ -126,15 +123,15 @@ export class UnRecursiveFileSystemWatcher extends Disposable implements IFileSys
126123
if ((type === 'rename' || type === 'change') && changeFileName === filename) {
127124
const fileExists = fs.existsSync(changePath);
128125
if (fileExists) {
129-
this.pushUpdated(watcherId, changePath);
126+
this.fileChangeCollectionManager.pushUpdated(watcherId, changePath);
130127
} else {
131128
docChildren.delete(changeFileName);
132-
this.pushDeleted(watcherId, changePath);
129+
this.fileChangeCollectionManager.pushDeleted(watcherId, changePath);
133130
}
134131
}
135132
} else if (fs.pathExistsSync(changePath)) {
136133
if (!fs.lstatSync(changePath).isDirectory()) {
137-
this.pushAdded(watcherId, changePath);
134+
this.fileChangeCollectionManager.pushAdded(watcherId, changePath);
138135
docChildren.add(changeFileName);
139136
}
140137
}
@@ -143,9 +140,9 @@ export class UnRecursiveFileSystemWatcher extends Disposable implements IFileSys
143140
setTimeout(async () => {
144141
if (changeFileName === signalDoc) {
145142
if (fs.pathExistsSync(basePath)) {
146-
this.pushUpdated(watcherId, basePath);
143+
this.fileChangeCollectionManager.pushUpdated(watcherId, basePath);
147144
} else {
148-
this.pushDeleted(watcherId, basePath);
145+
this.fileChangeCollectionManager.pushDeleted(watcherId, basePath);
149146
signalDoc = '';
150147
}
151148
}
@@ -212,36 +209,4 @@ export class UnRecursiveFileSystemWatcher extends Disposable implements IFileSys
212209
}
213210
return Promise.resolve();
214211
}
215-
216-
protected pushAdded(watcherId: number, path: string): void {
217-
this.pushFileChange(watcherId, path, FileChangeType.ADDED);
218-
}
219-
220-
protected pushUpdated(watcherId: number, path: string): void {
221-
this.pushFileChange(watcherId, path, FileChangeType.UPDATED);
222-
}
223-
224-
protected pushDeleted(watcherId: number, path: string): void {
225-
this.pushFileChange(watcherId, path, FileChangeType.DELETED);
226-
}
227-
228-
protected pushFileChange(watcherId: number, path: string, type: FileChangeType): void {
229-
const uri = FileUri.create(path).toString();
230-
231-
this.changes.get(watcherId).push({ uri, type });
232-
this.fireDidFilesChanged();
233-
}
234-
235-
/**
236-
* Fires file changes to clients.
237-
* It is debounced in the case if the filesystem is spamming to avoid overwhelming clients with events.
238-
*/
239-
protected readonly fireDidFilesChanged: () => void = debounce(() => this.doFireDidFilesChanged(), 100);
240-
241-
protected doFireDidFilesChanged(): void {
242-
this.changes.forEach((change, watcherId) => {
243-
const data = change.values();
244-
this.watcherGDataStore.emit(fileChangeEvent(watcherId), data);
245-
});
246-
}
247212
}

packages/utils/src/event.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,9 +1045,7 @@ export class Dispatcher<T = void> implements IDisposable {
10451045
}
10461046

10471047
dispose(): void {
1048-
if (this._emitter) {
1049-
this._emitter.dispose();
1050-
}
1048+
this._emitter.dispose();
10511049
}
10521050
}
10531051

0 commit comments

Comments
 (0)