@cocalc/project
Version:
CoCalc: project daemon
75 lines (61 loc) • 2.31 kB
text/coffeescript
#########################################################################
# This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
# License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details
#########################################################################
###
Watch a file for changes
Watch for changes to the given file. Returns obj, which
is an event emitter with events:
- 'change', ctime - when file changes or is created
- 'delete' - when file is deleted
and a method .close().
The ctime might be undefined, in case it can't be determined.
If debounce is given, only fires after the file
definitely has not had its ctime changed
for at least debounce ms. Does NOT fire when
the file first has ctime changed.
###
fs = require('fs')
{EventEmitter} = require('events')
class exports.Watcher extends EventEmitter
constructor: (path, interval, debounce) ->
super()
@path = path
@interval = interval
@debounce = debounce
fs.watchFile(@path, {interval: @interval, persistent:false}, @_listen)
close: () =>
@removeAllListeners()
fs.unwatchFile(@path, @listener)
_listen: (curr, prev) =>
if curr.dev == 0
@emit('delete')
return
if @debounce
@_emit_when_stable(true)
else
fs.stat @path, (err, stats) =>
if not err
@emit('change', stats.ctime)
_emit_when_stable: (first) =>
###
@_emit_when_stable gets called
periodically until the last ctime of the file
is at least @debounce ms in the past, or there
is an error.
###
if first and @_waiting_for_stable
return
@_waiting_for_stable = true
fs.stat @path, (err, stats) =>
if err
# maybe file deleted; give up.
delete @_waiting_for_stable
return
elapsed = new Date() - stats.ctime
if elapsed < @debounce
# File keeps changing - try again soon
setTimeout((=>@_emit_when_stable(false)), Math.max(500, @debounce - elapsed + 100))
else
delete @_waiting_for_stable
@emit('change', stats.ctime)