• This repository has been archived on 14/Feb/2020
  • Stars
    star
    104
  • Rank 330,604 (Top 7 %)
  • Language
    Scala
  • License
    MIT License
  • Created over 11 years ago
  • Updated almost 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

File-watching library for Scala. Built on Java 7's WatchService, RxScala and Akka actors.

Schwatcher Build Status Maven Central

Note: Requires Java8+ because the WatchService API is an essential part of this library along with Akka (Akka 2.4.x dropped support for Java7)

TL;DR A library that wraps the WatchService API. of Java7. You can choose to send callbacks to be registered on paths (both directories and files) or turn path events into a composable asynchronous data stream (RxScala Observable). For details, check out the Example usage section below.

As of Java7, the WatchService API was introduced to allow developers to monitor the file system without resorting to an external library/dependency like JNotify. Unfortunately, it requires you to use a loop that blocks in order to retrieve events from the API and does not have recursion support built-in.

Schwatcher will allow you to instantiate an Akka actor, register callbacks (functions that take a Path and return Unit) to be fired for certain Paths and event types by sending messages to it, then simply wait for the callbacks to be fired. Alternatively, use the Observable interface to register for notifications on paths.

The goal of Schwatcher is to facilitate the use of the Java7 API in Scala in a simple way that is in line with the functional programming paradigm.

As of now, Scala 2.11.x and 2.12.x are supported (Akka 2.4.x dropped support for 2.10.x)

Installation

Add the following to your build.sbt

libraryDependencies += "com.beachape.filemanagement" %% "schwatcher" % "0.3.2"

If the above does not work because it cannot be resolved, its likely because it hasn't been synced to Maven central yet. In that case, download a SNAPSHOT release of the same version by adding this to build.sbt

resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"

libraryDependencies += "com.beachape.filemanagement" %% "schwatcher" % "0.3.2-SNAPSHOT"

Those using Akka 2.1.x should stay on 0.0.2 as 0.0.3 onwards uses Akka 2.2.x, which requires some work to upgrade to.

Those using Akka 2.2.x should stay on 0.0.9 as 0.0.10 onwards uses Akka 2.3.x, which may require some work to upgrade to.

0.1.0 brings with it breaking changes on how to register callbacks (see example). Please be aware when upgrading from 0.0.x releases.

Those using Akka 2.3.x should stay on 0.1.x as 0.2.x onwards uses Akka 2.4.x, which requires Java8 and Scala 2.11.x

Example Usage

Akka

The basic workflow is:

  1. Instantiate a MonitorActor
  2. Register callbacks by sending RegisterCallback messages to the MonitorActor
  3. Carry on
  • Optionally, you can un-register all callbacks for a path and event type by sending UnRegisterCallback messages.
  • Both RegisterCallback and UnRegisterCallback messages have a recursive argument (be sure to see point 5 in the Caveats section) that triggers recursive registration and un-registration of callbacks for path.
import akka.actor.ActorSystem
import com.beachape.filemanagement.MonitorActor
import com.beachape.filemanagement.RegistryTypes._
import com.beachape.filemanagement.Messages._

import java.io.{FileWriter, BufferedWriter}

import java.nio.file.Paths
import java.nio.file.StandardWatchEventKinds._

implicit val system = ActorSystem("actorSystem")
val fileMonitorActor = system.actorOf(MonitorActor(concurrency = 2))

val modifyCallbackFile: Callback = { path => println(s"Something was modified in a file: $path")}
val modifyCallbackDirectory: Callback = { path => println(s"Something was modified in a directory: $path")}

val desktop = Paths get "/Users/lloyd/Desktop"
val desktopFile = Paths get "/Users/lloyd/Desktop/test"

/*
  This will receive callbacks for just the one file
*/
fileMonitorActor ! RegisterCallback(
  event = ENTRY_MODIFY,
  path = desktopFile,
  callback =  modifyCallbackFile
  )

/*
  If desktopFile is modified, this will also receive a callback
  it will receive callbacks for everything under the desktop directory
*/
fileMonitorActor ! RegisterCallback(
  event = ENTRY_MODIFY,
  path = desktop,
  callback = modifyCallbackDirectory)


//modify a monitored file
val writer = new BufferedWriter(new FileWriter(desktopFile.toFile))
writer.write("Theres text in here wee!!")
writer.close

// #=> Something was modified in a file: /Users/lloyd/Desktop/test.txt
//     Something was modified in a directory: /Users/lloyd/Desktop/test.txt

RxScala

There is another way to monitor files supported by this library: via Rx Observables.

This is neat because it allows you to treat notifications for files as, well, an Observable, which conceptually is like a Stream, or a Go channel. You can filter on the stream, map on it, filter on it ... basically compose it as you would a normal observable.

Note that since RxMonitor is powered by an Akka actor under the covers, the changes to what you (do not) want to monitor are done in a thread-safe manner so feel free to pass this object around.

import com.beachape.filemanagement.RxMonitor
import java.io.{FileWriter, BufferedWriter}

import java.nio.file.Paths
import java.nio.file.StandardWatchEventKinds._

val monitor = RxMonitor()
val observable = monitor.observable

val subscription = observable.subscribe(
  onNext = { p => println(s"Something was modified in a file mufufu: $p")},
  onError = { t => println(t)},
  onCompleted = { () => println("Monitor has been shut down") }
)

val desktopFile = Paths get "/Users/lloyd/Desktop/test"

monitor.registerPath(ENTRY_MODIFY, desktopFile)

Thread.sleep(100)

//modify a monitored file
val writer = new BufferedWriter(new FileWriter(desktopFile.toFile))
writer.write("Theres text in here wee!!")
writer.close

// #=> Something was modified in a file mufufu: /Users/lloyd/Desktop/test

// stop monitoring
monitor.stop()

// #=> Monitor has been shut down

Caveats

Above all things understand that library relies on the Java7 WatchService API and has the same constraints, limitations, and behaviours according to the implementation for the version of JVM you're using.

Additional library-specific caveats and notes are:

  1. Callbacks are registered for specific paths, and for directory paths, can be registered as recursive so that a single callback is fired when an event occurs inside the directory tree.
  2. Callbacks are not checked for uniqueness when registered to a specific path.
  3. A specific path can have multiple callbacks registered to a file event types, all will be fired.
  4. Callbacks are not guaranteed to be fired in any particular order unless if concurrency is set to 1 on the MonitorActor.
  5. Any event on a file path will bubble up to its immediate parent folder path. This means that if both a file and it's parent directory are registered for callbacks, both sets of callbacks will be fired.

As a result of note 6, you may want to think twice about registering recursive callbacks for ENTRY_DELETE because if a directory is deleted within a directory, 2 callbacks will be fired, once for the path registered for the deleted directory and once for the path registered for the directory above it (its parent directory).

Contributors

IDE Sponsor

Jetbrains sponsors this project through their Open Source licence, which has been an immensely helpful tool for all of my Scala development, at home and at work.

IntelliJ IDEA

More Repositories

1

frunk

Funktional generic type-level programming in Rust: HList, Coproduct, Generic, LabelledGeneric, Validated, Monoid and friends.
Rust
1,280
star
2

enumeratum

A type-safe, reflection-free, powerful enumeration implementation for Scala with exhaustive pattern match warnings and helpful integrations.
Scala
1,163
star
3

diesel

Boilerplate-free, zero-overhead Tagless Final / typed-final / Finally Tagless DSLs in Scala
Scala
110
star
4

slim-play

Slim Play app
Scala
76
star
5

rhodddoobie

My little sandbox for playing around with the FP + OOP + DDD combination, in particular using Rho, doobie, Docker, testing, etc in a project.
Scala
43
star
6

ansible-kafka-cluster

Zookeeper quorum + Kafka cluster on CentOS via Vagrant + Ansible
42
star
7

rusqbin

A server that stashes your requests for later retrieval so you can do end-to-end testing of code that makes HTTP calls. Available as a binary, a Docker image, and a library.
Rust
26
star
8

zipkin-futures

Zipkin tracing for Scala Futures and non-Futures (synchronous operations)
Scala
21
star
9

push_to_devices

Ruby-based ( Padrino / Sinatra ) server for pushing notifications to iOS and Android devices via Apple Push Notifications (APN) and Google Cloud Message (GCM) respectively.
Ruby
18
star
10

todddo-openapi-rs

Survey of the Rust web scene in mid-2019, covering async/await, DDD-esque structure, testing, mocking, OpenAPI, and Actix
Rust
17
star
11

freAST

Fast, simple Free Monads using ScalaMeta macro annotations. Port of Freasy-Monad.
Scala
14
star
12

sbt-opencv

Start using OpenCV in your JVM project in just 1 line, no separate compiling, installing OpenCV, or fussing with your system required.
Scala
13
star
13

sparkka-streams

Power a Spark Stream from anywhere in your Akka Stream Flow
Scala
12
star
14

metascraper-service

A completely non-blocking RESTful Play2 based API application that uses the Metascraper library to scrape URLs for metadata.
Scala
12
star
15

http4s-doobie-docker-scratchpad

Playing around with http4s + doobie + docker
Scala
11
star
16

ltsv-logger

Convenient and performant logging in LTSV for Scala
Scala
10
star
17

tasques

Background Tasks system backed by Elasticsearch with support for language agnostic Workers.
Go
9
star
18

finnhub-ws-rs

UI for finnhub.io live trades websocket API, written in Rust, compiled to WASM
Rust
8
star
19

scala-akka-cv-part1

Scala, Akka, Streams, JavaCV, OpenCV O MY! Part 1
Scala
7
star
20

scala-akka-cv-part2

Scala, Akka, Streams, JavaCV, OpenCV O MY! Part 2
Scala
7
star
21

chase-rs

Async + Sync file-following for people who care about file rotations and line numbers.
Rust
7
star
22

ansible-thumbor-centos

Ansible playbook for CentOS.
Shell
7
star
23

spray-servlet-scratchpad

Where I try to play around with Spray+Servlet
JavaScript
6
star
24

jhhi

Java Heap Histogram Ingest, written in Rust. Sends jmap heap histograms to Elasticsearch.
Rust
6
star
25

unless-when

`unless` and `when` macros for Scala 2.10+.
Scala
5
star
26

gol-rs

Conway's Game of Life in Rust + OpenGL
Rust
5
star
27

push_to_devices_rb

Ruby library for interfacing with Push to Devices server (https://github.com/lloydmeta/push_to_devices)
Ruby
5
star
28

centos-spark-cluster

CentOS w/ Zookeeper quorum and Spark cluster
5
star
29

seed-scala.g8

A basic skeleton Scala project
Scala
4
star
30

cogs

WIP client for MS Congitive services using async Hyper
Rust
4
star
31

actix-jwt-authc

JWT authentication middleware for Actix with support for JWT invalidation and custom Claims structs.
Rust
4
star
32

hash_walker

A simple gem that allows you to traverse/walk a Hash (perhaps obtained from doing JSON::parse on a JSON string) according to a set of keys (also a hash), passing in a block to perform actions.
Ruby
4
star
33

provide

@provide Scala annotation so you can annotate abstract method implementations safely instead of abusing `override`
Scala
4
star
34

aoc2021-rs

Advent of Code 2021 solutions in Rust
Rust
3
star
35

scalameta.g8

sbt/Giter8 starter template for Scala.meta.
Scala
3
star
36

play-csv

CSV Path, Query, and Form binders for Play 2 framework apps.
Scala
3
star
37

bloxi

A Blockchain implementation in Rust, following the "Learn Blockchains by Building One" tutorial.
Rust
3
star
38

redis-cleaner

A simple way of cleaning up a large number of Redis keys via [pattern matching](http://redis.io/commands/keys)
Ruby
2
star
39

pseudo_encrypt-rs

A native Rust generic implementation of the pseudo_encrypt function from Psql
Rust
2
star
40

Olivetti-PNG

Olivetti face set in PNG form
2
star
41

ctdi-play.g8

Compile-time DI Play template
Scala
2
star
42

sloword2vec-rs

A naive (read: slow) implementation of Word2Vec. Uses BLAS behind the scenes for speed.
Rust
2
star
43

todddo-openapi

Exploring DDD, dependency-management, testing, web in the world of Golang.
Go
2
star
44

hystrix-scala-scratchpad

Lloyd's Hystrix playground. Exploring Scala + Hystrix.
Scala
2
star
45

Risp

Reduced-Lisp in Scala Processor, Risp, is a simplified, type-safe, stack-safe Lisp written in Scala.
Scala
2
star
46

todddo-openapi-java

An exploration of modern Java API dev by building a reactive non-trivial app with DDD-esque structuring.
Java
2
star
47

mune

Scala
1
star
48

fib-hs

Playing around with Haskell Stack toolbelt, asking questions
Haskell
1
star
49

elasticsearch-rs

Elasticsearch Rust Client
Rust
1
star
50

iBabble

Mobile client for Babble
Objective-C
1
star
51

aoc2020-rs

Advent of Code 2020 solutions in Rust
Rust
1
star
52

lloydmeta.github.io

HTML
1
star
53

bloop-with-gradle-and-silencer

Min repro
Kotlin
1
star
54

bloop-gradle-subprojects

Repro
Kotlin
1
star
55

bloop-on-gradle-with-its

A min repro of the bloop Gradle plugin not adding test frameworks to an integration test configuration
Java
1
star
56

slim-play.g8

Giter8 template for a slim Play app
Scala
1
star
57

ngrams-enabler

A simple way of getting ngrams out of any given String object. Supports CJK (Chinese, Japanese, Korean) as well as alphabet based languages.
Ruby
1
star
58

ip-parsing-hs

Playing around with parsers in Haskell
Haskell
1
star
59

slim-play-activator

Activator template for a Slim Play project
Scala
1
star
60

play-chatroom

Super simple websockets, Play framework chatroom w/ actors.
Scala
1
star
61

reculture-shields

Super simple shields for Re:Culture.
Scala
1
star
62

gander

An HTML content extractor. Forked from a fork of Goose.
Scala
1
star
63

thumbor-intro

HTML
1
star
64

sbt-javacpp

Use JavaCPP and JavaCPP presets with ease. Base plugin for JavaCPP-related projects.
Scala
1
star
65

akanori-thrift

Thrift server version of akanori
Java
1
star
66

huggingface_elasticsearch_rag

Cookbook for building an Elasticsearch and Gemma-powered RAG via Huggingface models and APIs
Jupyter Notebook
1
star
67

opa-gungnamstyle-scratchpad

OPA exploration
Open Policy Agent
1
star