forked from pathikrit/better-files
-
Notifications
You must be signed in to change notification settings - Fork 0
/
FileWatcher.scala
67 lines (50 loc) · 2.48 KB
/
FileWatcher.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package better.files
import akka.actor._
/**
* An actor that can watch a file or a directory
* Instead of directly calling the constructor of this, call file.newWatcher to create the actor
*
* @param file watch this file (or directory)
* @param maxDepth In case of directories, how much depth should we watch
*/
class FileWatcher(file: File, maxDepth: Int) extends Actor {
import FileWatcher._
def this(file: File, recursive: Boolean = true) = this(file, if (recursive) Int.MaxValue else 0)
protected[this] val callbacks = newMultiMap[Event, Callback]
protected[this] val monitor: File.Monitor = new FileMonitor(file, maxDepth) {
override def onEvent(event: Event, file: File, count: Int) = self ! Message.NewEvent(event, file, count)
override def onException(exception: Throwable) = self ! Status.Failure(exception)
}
override def preStart() = monitor.start()(executionContext = context.dispatcher)
override def receive = {
case Message.NewEvent(event, target, count) if callbacks.contains(event) => callbacks(event).foreach(f => repeat(count)(f(event -> target)))
case Message.RegisterCallback(events, callback) => events.foreach(event => callbacks.addBinding(event, callback))
case Message.RemoveCallback(event, callback) => callbacks.removeBinding(event, callback)
}
override def postStop() = monitor.stop()
}
object FileWatcher {
import java.nio.file.{Path, WatchEvent}
type Event = WatchEvent.Kind[Path]
type Callback = PartialFunction[(Event, File), Unit]
sealed trait Message
object Message {
case class NewEvent(event: Event, file: File, count: Int) extends Message
case class RegisterCallback(events: Traversable[Event], callback: Callback) extends Message
case class RemoveCallback(event: Event, callback: Callback) extends Message
}
implicit val disposeActorSystem: Disposable[ActorSystem] =
Disposable(_.terminate())
implicit class FileWatcherOps(file: File) {
def watcherProps(recursive: Boolean): Props =
Props(new FileWatcher(file, recursive))
def newWatcher(recursive: Boolean = true)(implicit system: ActorSystem): ActorRef =
system.actorOf(watcherProps(recursive))
}
def when(events: Event*)(callback: Callback): Message =
Message.RegisterCallback(events, callback)
def on(event: Event)(callback: File => Unit): Message =
when(event) { case (`event`, file) => callback(file) }
def stop(event: Event, callback: Callback): Message =
Message.RemoveCallback(event, callback)
}