svc.fnl (1652B)
1 (local inotify (require :inotify)) 2 (local { : file-exists? } (require :anoia)) 3 (local { : directory? } (require :anoia.fs)) 4 (local lfs (require :lfs)) 5 6 (fn read-line [name] 7 (with-open [f (assert (io.open name :r) (.. "can't open file " name))] 8 (f:read "*l"))) 9 10 (fn watch-fsevents [directory-name] 11 (let [handle (inotify.init)] 12 (handle:addwatch directory-name 13 inotify.IN_CREATE 14 inotify.IN_MOVE 15 inotify.IN_DELETE 16 inotify.IN_DELETE_SELF 17 inotify.IN_MOVED_FROM 18 inotify.IN_MOVED_TO 19 inotify.IN_CLOSE_WRITE) 20 handle)) 21 22 (fn read-value [pathname] 23 (case (lfs.symlinkattributes pathname) 24 nil nil 25 {:mode "directory"} 26 (collect [f (lfs.dir pathname)] 27 (when (not (or (= f ".") (= f ".."))) 28 (values f (read-value ( .. pathname "/" f))))) 29 {:mode "file"} 30 (read-line pathname) 31 {:mode "link"} 32 (read-line pathname) 33 unknown 34 (error (.. "can't read " pathname " of kind \"" unknown.mode "\"")))) 35 36 (fn events [self] 37 (coroutine.wrap 38 #(while true 39 (while (not (self:ready?)) (self:wait)) 40 (coroutine.yield self) 41 (self:wait)))) 42 43 (fn open [directory] 44 (let [watcher (watch-fsevents directory) 45 has-file? (fn [filename] (file-exists? (.. directory "/" filename)))] 46 { 47 :wait #(watcher:read) 48 :ready? (fn [self] 49 (and (has-file? "state") (not (has-file? ".lock")))) 50 :output (fn [_ filename] 51 (read-value (.. directory "/" filename))) 52 :close #(watcher:close) 53 : events 54 })) 55 56 { : open }