ionian/src/diff/watcher.ts
2021-02-22 23:09:55 +09:00

78 lines
No EOL
2.5 KiB
TypeScript

import { FSWatcher, watch } from 'fs';
import { promises } from 'fs';
import event from 'events';
const readdir = promises.readdir;
interface DiffWatcherEvent{
'create':(filename:string)=>void,
'delete':(filename:string)=>void,
'change':(prev_filename:string,cur_filename:string)=>void,
}
export interface IDiffWatcher extends event.EventEmitter {
on<U extends keyof DiffWatcherEvent>(event:U,listener:DiffWatcherEvent[U]): this;
emit<U extends keyof DiffWatcherEvent>(event:U,...arg:Parameters<DiffWatcherEvent[U]>): boolean;
readonly path: string;
}
export class CommonDiffWatcher extends event.EventEmitter implements IDiffWatcher{
on<U extends keyof DiffWatcherEvent>(event:U,listener:DiffWatcherEvent[U]): this{
return super.on(event,listener);
}
emit<U extends keyof DiffWatcherEvent>(event:U,...arg:Parameters<DiffWatcherEvent[U]>): boolean{
return super.emit(event,...arg);
}
private _path:string;
private _watcher: FSWatcher|null;
constructor(path:string){
super();
this._path = path;
this._watcher = null;
}
public get path(){
return this._path;
}
/**
* setup
* @argument initial_filenames filename in path
*/
async setup(initial_filenames:string[]){
const cur = (await readdir(this._path,{
encoding:"utf8",
withFileTypes: true,
})).filter(x=>x.isFile).map(x=>x.name);
//Todo : reduce O(nm) to O(n+m) using hash map.
let added = cur.filter(x => !initial_filenames.includes(x));
let deleted = initial_filenames.filter(x=>!cur.includes(x));
for (const iterator of added) {
this.emit('create',iterator);
}
for (const iterator of deleted){
this.emit('delete',iterator);
}
}
watch():FSWatcher{
this._watcher = watch(this._path,{persistent: true, recursive:false},async (eventType,filename)=>{
if(eventType === "rename"){
const cur = (await readdir(this._path,{
encoding:"utf8",
withFileTypes: true,
})).filter(x=>x.isFile).map(x=>x.name);
//add
if(cur.includes(filename)){
this.emit('create',filename);
}
else{
this.emit('delete',filename)
}
}
});
return this._watcher;
}
watchClose(){
this._watcher?.close()
}
}