BrowserFS
BrowserFS copied to clipboard
filesystem watch
how about a watch API?
I'd accept PRs for this.
If you only care about local modifications to the filesystem (meaning: you don't care about watching Dropbox files for changes, or another browser tab interfacing with your IndexedDB store), we could integrate this into the fs API emulation layer:
- Sync API: If relevant operation successfully completes on a watched file,
setImmediatea watch event. - Async API: If watch is enabled for the file, wrap the callback to check if it succeeded. If so,
setImmediatea watch event.
For non-local changes, we'd have to figure out a change to the FileSystem interface.
Subtleties:
- For file descriptor operations, we should only emit
changeevents when a change is written to the file store. Most BrowserFS file systems wait until a file is closed to sync the changes. We can augment theFileinterface so that it's possible to watch a particular file descriptor, and then changeBaseFileto emit a watch event onsync.
I too am interested in this. Currently I'm monkey-patching fs.writeFile and fs.writeFileSync to fire events when files are saved.
Am now monkey-patching fs.mkdir and fs.mkdirSync, will inevitably need to monkey-patch rmdir, rmdirSync, unlink, and unlinkSync. However I've run into a conundrum:
The Node.js fs.watch API sucks.
It is literally quite useless. It only has one event, change1, and one value filename. The event does not tell you 1) whether filename is a directory or a file 2) whether it was added, deleted, or modified.
This pretty much necessitates doing a second call with fs.stat or even a third with fs.readdir to determine what happened, which seems ~~like a waste.~~ error prone and inefficient.
To overcome the failings of the Node API, naturally most projects use a wrapper library. The most popular seems to be chokidar (2149 dependents) but there is a long tail of others: watch (510 dependents), gaze (363 dependents) watchr (124 dependents), sane (75 dependents), filewatcher (28 dependents)... and they each use their own naming scheme for file system "events".
Right now I'm leaning toward implementing the chokidar event names (which are 'add', 'change', 'unlink', 'addDir', and 'unlinkDir') or using a novel-but-impartial event naming scheme based on the function names ('write', 'rename', 'unlink', 'mkdir', 'rmdir'). The former has the advantage of not inventing another wheel, and would be familiar to (some) Node users. The latter has the advantage that I could just as easily add ('read', 'readdir', 'stat', 'open', 'close', 'symlink', 'chown', 'chmod', etc) events which could be valuable, and I wouldn't have to think twice about what to name events.
Any thoughts on what would be the most useful to others? Eventually I figure I could release the result of my monkey-patching as a BrowserFSWatcher package, but it would be cleaner if there were some hooks in BrowserFS for implementing watchers on top of it. fs.watch seems to be a terrible hook though.
1 technically it also has a "rename" event but it is weirdly inconsistant
I am highly interested in this
@wmhilton do you have any snippets you can share of your monkey patching that you did? I think even as a monkey patch solution, could provide value to the community :)
I've also been revisiting this question occasionally over the past year, in hope that progress had been made.
In my case I only have the need for watching local changes.
Here's a monkey patch I'm using:
const EventEmitter = require("events");
const fsEventEmitter = new EventEmitter();
Object.keys(fs).filter(k => typeof fs[k] === "function").forEach(k => {
const orig = fs[k];
fs[k] = (...args) => {
fsEventEmitter.emit(k, ...args);
return orig(...args);
}
})
It'll emit events for every function call, so you can listen for those and handle them accordingly.
Please use https://github.com/browser-fs/core/issues/6