diff --git a/README.md b/README.md index e3f9d814..7eda1af4 100644 --- a/README.md +++ b/README.md @@ -39,4 +39,4 @@ For example if you want to use the `orx-no-clear` artifact one would use: dependencies { compile 'com.github.openrndr.orx:orx-no-clear:v0.0.20' } -``` +``` \ No newline at end of file diff --git a/build.gradle b/build.gradle index d263776d..2722b0f5 100644 --- a/build.gradle +++ b/build.gradle @@ -1,67 +1,67 @@ -plugins { - id 'org.jetbrains.kotlin.jvm' version '1.3.10' -} - -allprojects { - group 'org.openrndr.extra' - version '0.0.20' -} - -repositories { - mavenLocal() - mavenCentral() -} - -ext { - openrndrVersion = "0.3.32-rc4" -} - -subprojects { - - apply plugin: 'kotlin' - apply plugin: 'maven' - apply plugin: 'maven-publish' - repositories { - mavenLocal() - mavenCentral() - maven { - url = "https://dl.bintray.com/openrndr/openrndr" - } - } - - dependencies { - compile "org.openrndr:openrndr-core:$openrndrVersion" - compile "org.openrndr:openrndr-filter:$openrndrVersion" - compile "org.openrndr:openrndr-shape:$openrndrVersion" - compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.0.1' - } - - publishing { - publications { - mavenJava(MavenPublication) { - from components.java - - artifact sourceJar - } - } - } - - task sourceJar(type: Jar) { - classifier = 'sources' - from sourceSets.main.kotlin - } - - - -} - -dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8" -} - -compileKotlin { - kotlinOptions.jvmTarget = "1.8" -} -compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" +plugins { + id 'org.jetbrains.kotlin.jvm' version '1.3.10' +} + +allprojects { + group 'org.openrndr.extra' + version '0.0.22' +} + +repositories { + mavenLocal() + mavenCentral() +} + +ext { + openrndrVersion = "0.3.33-rc1" +} + +subprojects { + + apply plugin: 'kotlin' + apply plugin: 'maven' + apply plugin: 'maven-publish' + repositories { + mavenLocal() + mavenCentral() + maven { + url = "https://dl.bintray.com/openrndr/openrndr" + } + } + + dependencies { + compile "org.openrndr:openrndr-core:$openrndrVersion" + compile "org.openrndr:openrndr-filter:$openrndrVersion" + compile "org.openrndr:openrndr-shape:$openrndrVersion" + compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.0.1' + } + + publishing { + publications { + mavenJava(MavenPublication) { + from components.java + + artifact sourceJar + } + } + } + + task sourceJar(type: Jar) { + classifier = 'sources' + from sourceSets.main.kotlin + } + + + +} + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8" +} + +compileKotlin { + kotlinOptions.jvmTarget = "1.8" +} +compileTestKotlin { + kotlinOptions.jvmTarget = "1.8" } \ No newline at end of file diff --git a/orx-file-watcher/README.md b/orx-file-watcher/README.md new file mode 100644 index 00000000..3bfbcdb6 --- /dev/null +++ b/orx-file-watcher/README.md @@ -0,0 +1,37 @@ +# orx-file-watcher + +A file watcher for OPENRNDR + +## Usage + +Monitoring a single file. + +```kotlin +application { + program { + val watchedText = watchFile(File("someFile.txt")) { + it.readText() + } + extend { + val theText = watchedText() + } + } +} +``` + +Making a map of monitored files. + +```kotlin +application { + program { + val watchedTexts = mutableMapString>() + watchedTexts["text"] = watchFile(File("someFile.txt")) { + it.readText() + } + + extend { + val theText = watchedTexts.getValue("text")() + } + } +} +``` diff --git a/orx-file-watcher/src/main/kotlin/FileWatcher.kt b/orx-file-watcher/src/main/kotlin/FileWatcher.kt new file mode 100644 index 00000000..3fd21ac8 --- /dev/null +++ b/orx-file-watcher/src/main/kotlin/FileWatcher.kt @@ -0,0 +1,93 @@ +package org.operndr.extras.filewatcher + +import com.sun.nio.file.SensitivityWatchEventModifier +import org.openrndr.Program +import org.openrndr.launch +import java.io.File +import java.nio.file.FileSystems +import java.nio.file.Path +import java.nio.file.StandardWatchEventKinds +import java.nio.file.WatchKey +import kotlin.concurrent.thread + +class FileWatcher(private val program: Program, val file: File, private val onChange: (File) -> Unit) { + init { + watchThread + val path = file.absoluteFile.toPath() + val parent = path.parent + val key = pathKeys.getOrPut(parent) { + parent.register( + watchService, arrayOf(StandardWatchEventKinds.ENTRY_MODIFY), + SensitivityWatchEventModifier.HIGH + ) + } + watching.getOrPut(path) { + mutableListOf() + }.add(this) + keyPaths.getOrPut(key) { parent } + } + + internal fun triggerChange() { + program.launch { + onChange(file) + } + } +} + +fun watchFile(program: Program, file: File, transducer: (File) -> T): () -> T { + var result = transducer(file) + FileWatcher(program, file) { + try { + result = transducer(file) + } catch (e: Throwable) { + e.printStackTrace() + } + } + return { + result + } +} + +@JvmName("programWatchFile") +fun Program.watchFile(file: File, transducer: (File) -> T): () -> T = watchFile(this, file, transducer) + +private val watching = mutableMapOf>() +private val pathKeys = mutableMapOf() +private val keyPaths = mutableMapOf() + +private val watchService by lazy { + FileSystems.getDefault().newWatchService() +} + +private val watchThread by lazy { + thread(isDaemon = true) { + while (true) { + val key = watchService.take() + val path = keyPaths[key] + key.pollEvents().forEach { + val contextPath = it.context() as Path + val fullPath = path?.resolve(contextPath) + watching[fullPath]?.forEach { + + it.triggerChange() + } + } + key.reset() + } + } +} + +fun main() { + val a = watchFile(Program(), File("README.md")) { + it.readText() + } + + + + while (true) { + println(a()) + Thread.sleep(2000) + + } +} + diff --git a/settings.gradle b/settings.gradle index 4762ec10..29230e50 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,6 +2,7 @@ rootProject.name = 'orx' include 'orx-camera', 'orx-compositor', + 'orx-file-watcher', 'orx-filter-extension', 'orx-integral-image', 'orx-jumpflood', @@ -13,3 +14,4 @@ include 'orx-camera', +