import { watch , FSWatcher } from "fs" ; import { join } from "path" ; import { EventEmitter } from "events" ; import { debounce } from "lodash" ; import { exists } from "../jupyter/async-utils-node" ; import { close , path_split } from "@cocalc/util/misc" ; export class Watcher extends EventEmitter { private path : string ; private exists : boolean ; private watch_contents ? : FSWatcher ; private watch_existence ? : FSWatcher ; private debounce_ms : number ; private log : Function ; constructor ( path , debounce_ms , log ) { super ( ) ; this . debounce_ms = debounce_ms ; this . log = log ; this . log ( `Watcher("${ path }")` ) ; if ( process . env . HOME == null ) throw Error ( "bug -- HOME must be defined" ) ; this . path = join ( process . env . HOME , path ) ; this . init ( ) ; } private async init ( ) { this . exists = await exists ( this . path ) ; if ( this . path != "" ) { this . init_watch_existence ( ) ; } if ( this . exists ) { this . init_watch_contents ( ) ; } } private init_watch_contents ( ) { this . watch_contents = watch ( this . path , debounce ( this . change . bind ( this ) , this . debounce_ms , { leading : true , trailing : true , } ) ) ; } private async init_watch_existence ( ) { const containing_path = path_split ( this . path ) . head ; this . watch_existence = watch ( containing_path , async ( _ , filename ) => { const path = join ( containing_path , filename ) ; if ( path != this . path ) return ; const e = await exists ( this . path ) ; if ( ! this . exists && e ) { this . exists = e ; this . init_watch_contents ( ) ; this . change ( ) ; } else if ( this . exists && ! e ) { this . exists = e ; if ( this . watch_contents != null ) { this . watch_contents . close ( ) ; delete this . watch_contents ; } this . change ( ) ; } } ) ; } private change ( ) { this . emit ( "change" ) ; } public close ( ) { if ( this . watch_contents != null ) { this . watch_contents . close ( ) ; } if ( this . watch_existence != null ) { this . watch_existence . close ( ) ; } close ( this ) ; } }