Skip to content

Instantly share code, notes, and snippets.

@hugoduncan
Created August 30, 2013 19:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hugoduncan/6393438 to your computer and use it in GitHub Desktop.
Save hugoduncan/6393438 to your computer and use it in GitHub Desktop.
Using JDK Watch Service
(ns com.palletops.brick-server.fs-watch
"Watch a filesystem path"
(:require
[clojure.java.io :refer [file]]
[clojure.set :refer [map-invert]]
[clojure.tools.logging :refer [debugf]]
[clojure.string :refer [join]])
(:import
[java.nio.file
ClosedWatchServiceException FileSystems Path StandardWatchEventKinds
WatchEvent WatchEvent$Kind WatchService]))
(def event-kind {:create StandardWatchEventKinds/ENTRY_CREATE
:delete StandardWatchEventKinds/ENTRY_DELETE
:modify StandardWatchEventKinds/ENTRY_MODIFY})
(def event-kw (map-invert event-kind))
(defn- event->map [^WatchEvent event]
{:kind (get event-kw (.kind event))
:path (.context event)})
(defn ^Path path [f]
"Return a java.io.file.Path for the specified file."
(.getPath
(FileSystems/getDefault) (.getAbsolutePath (file f)) (into-array String [])))
(defn watch-seq*
"Returns a lazy sequence of events from the given watch-service."
[^WatchService watch-service]
(lazy-seq
(try
(let [watch-key (.take watch-service)
events (.pollEvents watch-key)]
(debugf "watch-seq* got events %s" events)
(let [events (mapv event->map events)]
(.reset watch-key)
(cons (first events)
(concat (rest events) (watch-seq* watch-service)))))
(catch ClosedWatchServiceException _))))
(defn watch-seq [file & event-kinds]
"Return a map with :watch-seq, a lazy sequence of events on file,
and :closeable, a closeable.
The events are generated according to the event-kinds, which should be one or
more of the keywords :create, :delete, or :modify.
Each event returned by the sequence is a map, with :event-kind and :path keys.
The watch-seq can be terminated by closing the :closeable value."
(when-not (every? (set (keys event-kind)) event-kinds)
(throw
(IllegalArgumentException.
(str "Invalid event-kind in " (join ", " event-kinds)))))
(let [path (path file)
watch-service (-> (.getFileSystem path) (.newWatchService))]
(.register path watch-service
(into-array WatchEvent$Kind (map event-kind event-kinds)))
{:watch-seq (watch-seq* watch-service) :closeable watch-service}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment