summaryrefslogtreecommitdiff
path: root/app/src/main/java/org/the_jk/cleversync
diff options
context:
space:
mode:
authorJoel Klinghed <the_jk@spawned.biz>2024-07-15 23:52:28 +0200
committerJoel Klinghed <the_jk@spawned.biz>2024-07-16 00:25:07 +0200
commit42564c71cfb70c28831c662a3b6bf4084e079353 (patch)
tree111456fd3e8dce884d0380a81d70950062c7d212 /app/src/main/java/org/the_jk/cleversync
parent4a8f6807c9d3ee6bcfac25aee832163036b4e6fe (diff)
Break out io code in libs
Preparing for adding more io implementations. Really tried writing the convention plugins in kotlin dsl but could not find the exact right hacks to get it to work.
Diffstat (limited to 'app/src/main/java/org/the_jk/cleversync')
-rw-r--r--app/src/main/java/org/the_jk/cleversync/LiveDataUtils.kt14
-rw-r--r--app/src/main/java/org/the_jk/cleversync/StringUtils.kt32
-rw-r--r--app/src/main/java/org/the_jk/cleversync/io/Directory.kt20
-rw-r--r--app/src/main/java/org/the_jk/cleversync/io/File.kt12
-rw-r--r--app/src/main/java/org/the_jk/cleversync/io/Link.kt13
-rw-r--r--app/src/main/java/org/the_jk/cleversync/io/ModifiableDirectory.kt28
-rw-r--r--app/src/main/java/org/the_jk/cleversync/io/ModifiableFile.kt7
-rw-r--r--app/src/main/java/org/the_jk/cleversync/io/ModifiableLink.kt15
-rw-r--r--app/src/main/java/org/the_jk/cleversync/io/ModifiableTree.kt3
-rw-r--r--app/src/main/java/org/the_jk/cleversync/io/Tree.kt7
-rw-r--r--app/src/main/java/org/the_jk/cleversync/io/TreeFactory.kt8
-rw-r--r--app/src/main/java/org/the_jk/cleversync/io/impl/PathDirectory.kt188
-rw-r--r--app/src/main/java/org/the_jk/cleversync/io/impl/PathFile.kt66
-rw-r--r--app/src/main/java/org/the_jk/cleversync/io/impl/PathLink.kt62
-rw-r--r--app/src/main/java/org/the_jk/cleversync/io/impl/PathTree.kt10
-rw-r--r--app/src/main/java/org/the_jk/cleversync/io/impl/PathWatcher.kt82
16 files changed, 5 insertions, 562 deletions
diff --git a/app/src/main/java/org/the_jk/cleversync/LiveDataUtils.kt b/app/src/main/java/org/the_jk/cleversync/LiveDataUtils.kt
deleted file mode 100644
index 7f6ab1f..0000000
--- a/app/src/main/java/org/the_jk/cleversync/LiveDataUtils.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.the_jk.cleversync
-
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.Observer
-
-fun <T> LiveData<T>.safeValue(): T? {
- if (this.hasActiveObservers())
- return value
- var ret: T? = null
- val observer = Observer<T> { value -> ret = value }
- this.observeForever(observer)
- this.removeObserver(observer)
- return ret
-}
diff --git a/app/src/main/java/org/the_jk/cleversync/StringUtils.kt b/app/src/main/java/org/the_jk/cleversync/StringUtils.kt
deleted file mode 100644
index 6adea24..0000000
--- a/app/src/main/java/org/the_jk/cleversync/StringUtils.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.the_jk.cleversync
-
-object StringUtils {
- fun split(input: String, delimiter: Char, keepEmpty: Boolean = true, limit: Int = 0): List<String> {
- return buildList {
- var offset = 0
- var count = 0
- while (true) {
- val next = input.indexOf(delimiter, offset)
- if (next == -1) {
- if (keepEmpty || offset < input.length) {
- if (limit > 0 && count == limit) {
- add("${removeLast()}${delimiter}${input.substring(offset)}")
- break
- }
- add(input.substring(offset))
- }
- break
- }
- if (keepEmpty || offset < next) {
- if (limit > 0 && count == limit) {
- add("${removeLast()}${delimiter}${input.substring(offset)}")
- break
- }
- add(input.substring(offset, next))
- count++
- }
- offset = next + 1
- }
- }
- }
-}
diff --git a/app/src/main/java/org/the_jk/cleversync/io/Directory.kt b/app/src/main/java/org/the_jk/cleversync/io/Directory.kt
deleted file mode 100644
index e653059..0000000
--- a/app/src/main/java/org/the_jk/cleversync/io/Directory.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.the_jk.cleversync.io
-
-import androidx.lifecycle.LiveData
-
-interface Directory {
- val name: String
-
- fun openDir(name: String): Directory?
- fun openFile(name: String): File?
- fun openLink(name: String): Link?
-
- fun list(): Content
- fun liveList(): LiveData<Content>
-
- data class Content(
- val directories: List<Directory>,
- val files: List<File>,
- val links: List<Link>,
- )
-}
diff --git a/app/src/main/java/org/the_jk/cleversync/io/File.kt b/app/src/main/java/org/the_jk/cleversync/io/File.kt
deleted file mode 100644
index 17f142a..0000000
--- a/app/src/main/java/org/the_jk/cleversync/io/File.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.the_jk.cleversync.io
-
-import java.io.InputStream
-import java.time.Instant
-
-interface File {
- val name: String
- val size: ULong
- val lastModified: Instant
-
- fun read(): InputStream
-}
diff --git a/app/src/main/java/org/the_jk/cleversync/io/Link.kt b/app/src/main/java/org/the_jk/cleversync/io/Link.kt
deleted file mode 100644
index c05f29e..0000000
--- a/app/src/main/java/org/the_jk/cleversync/io/Link.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package org.the_jk.cleversync.io
-
-interface Link {
- val name: String
-
- fun resolve(): LinkTarget
-
- sealed class LinkTarget
-
- data class DirectoryTarget(val directory: Directory): LinkTarget()
- data class FileTarget(val file: File): LinkTarget()
- data object NoTarget: LinkTarget()
-}
diff --git a/app/src/main/java/org/the_jk/cleversync/io/ModifiableDirectory.kt b/app/src/main/java/org/the_jk/cleversync/io/ModifiableDirectory.kt
deleted file mode 100644
index 8bddc2c..0000000
--- a/app/src/main/java/org/the_jk/cleversync/io/ModifiableDirectory.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.the_jk.cleversync.io
-
-import androidx.lifecycle.LiveData
-
-interface ModifiableDirectory : Directory {
- fun modifiableOpenDir(name: String): ModifiableDirectory?
- fun modifiableOpenFile(name: String): ModifiableFile?
- fun modifiableOpenLink(name: String): ModifiableLink?
-
- fun modifiableList(): Content
- fun modifiableLiveList(): LiveData<Content>
-
- fun createDirectory(name: String): ModifiableDirectory
- fun createFile(name: String): ModifiableFile
- fun createLink(name: String, target: Directory): ModifiableLink
- fun createLink(name: String, target: File): ModifiableLink
- fun createLink(name: String, target: String): ModifiableLink
-
- fun removeDirectory(name: String): Boolean
- fun removeFile(name: String): Boolean
- fun removeLink(name: String): Boolean
-
- data class Content(
- val directories: List<ModifiableDirectory>,
- val files: List<ModifiableFile>,
- val links: List<ModifiableLink>,
- )
-}
diff --git a/app/src/main/java/org/the_jk/cleversync/io/ModifiableFile.kt b/app/src/main/java/org/the_jk/cleversync/io/ModifiableFile.kt
deleted file mode 100644
index 8675dae..0000000
--- a/app/src/main/java/org/the_jk/cleversync/io/ModifiableFile.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.the_jk.cleversync.io
-
-import java.io.OutputStream
-
-interface ModifiableFile : File {
- fun write(): OutputStream
-}
diff --git a/app/src/main/java/org/the_jk/cleversync/io/ModifiableLink.kt b/app/src/main/java/org/the_jk/cleversync/io/ModifiableLink.kt
deleted file mode 100644
index 7dd565b..0000000
--- a/app/src/main/java/org/the_jk/cleversync/io/ModifiableLink.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.the_jk.cleversync.io
-
-interface ModifiableLink : Link {
- fun modifiableResolve(): ModifiableLinkTarget
-
- fun target(directory: Directory)
- fun target(file: File)
- fun target(name: String)
-
- sealed class ModifiableLinkTarget
-
- data class ModifiableDirectoryTarget(val directory: ModifiableDirectory): ModifiableLinkTarget()
- data class ModifiableFileTarget(val file: ModifiableFile): ModifiableLinkTarget()
- data object NoTarget: ModifiableLinkTarget()
-}
diff --git a/app/src/main/java/org/the_jk/cleversync/io/ModifiableTree.kt b/app/src/main/java/org/the_jk/cleversync/io/ModifiableTree.kt
deleted file mode 100644
index 383360d..0000000
--- a/app/src/main/java/org/the_jk/cleversync/io/ModifiableTree.kt
+++ /dev/null
@@ -1,3 +0,0 @@
-package org.the_jk.cleversync.io
-
-interface ModifiableTree : Tree, ModifiableDirectory
diff --git a/app/src/main/java/org/the_jk/cleversync/io/Tree.kt b/app/src/main/java/org/the_jk/cleversync/io/Tree.kt
deleted file mode 100644
index b6f2d54..0000000
--- a/app/src/main/java/org/the_jk/cleversync/io/Tree.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.the_jk.cleversync.io
-
-import android.content.res.Resources
-
-interface Tree : Directory {
- fun description(resources: Resources): CharSequence
-}
diff --git a/app/src/main/java/org/the_jk/cleversync/io/TreeFactory.kt b/app/src/main/java/org/the_jk/cleversync/io/TreeFactory.kt
index d7c22f5..6df2c93 100644
--- a/app/src/main/java/org/the_jk/cleversync/io/TreeFactory.kt
+++ b/app/src/main/java/org/the_jk/cleversync/io/TreeFactory.kt
@@ -1,12 +1,14 @@
package org.the_jk.cleversync.io
-import org.the_jk.cleversync.io.impl.PathTree
+import org.the_jk.cleversync.local.LocalTreeFactory
import java.nio.file.Path
object TreeFactory {
fun localModifiableTree(root: Path): ModifiableTree {
- return PathTree(root)
+ return LocalTreeFactory.modifiableTree(root)
}
- fun localTree(root: Path): Tree = localModifiableTree(root)
+ fun localTree(root: Path): Tree {
+ return LocalTreeFactory.tree(root)
+ }
}
diff --git a/app/src/main/java/org/the_jk/cleversync/io/impl/PathDirectory.kt b/app/src/main/java/org/the_jk/cleversync/io/impl/PathDirectory.kt
deleted file mode 100644
index 55bed6a..0000000
--- a/app/src/main/java/org/the_jk/cleversync/io/impl/PathDirectory.kt
+++ /dev/null
@@ -1,188 +0,0 @@
-package org.the_jk.cleversync.io.impl
-
-import androidx.annotation.AnyThread
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.map
-import org.the_jk.cleversync.io.Directory
-import org.the_jk.cleversync.io.File
-import org.the_jk.cleversync.io.ModifiableDirectory
-import org.the_jk.cleversync.io.ModifiableFile
-import org.the_jk.cleversync.io.ModifiableLink
-import java.nio.file.LinkOption
-import java.nio.file.NoSuchFileException
-import java.nio.file.Path
-import kotlin.io.path.ExperimentalPathApi
-import kotlin.io.path.createDirectory
-import kotlin.io.path.createSymbolicLinkPointingTo
-import kotlin.io.path.deleteIfExists
-import kotlin.io.path.deleteRecursively
-import kotlin.io.path.isDirectory
-import kotlin.io.path.isRegularFile
-import kotlin.io.path.isSymbolicLink
-import kotlin.io.path.listDirectoryEntries
-import kotlin.io.path.name
-import kotlin.io.path.readSymbolicLink
-
-@OptIn(ExperimentalPathApi::class)
-internal open class PathDirectory(
- internal val path: Path,
- private val pathWatcher: PathWatcher,
-) : ModifiableDirectory {
- private val watcher: DirectoryWatcher by lazy {
- DirectoryWatcher()
- }
-
- private val modifiableLiveContent: LiveData<ModifiableDirectory.Content> by lazy {
- watcher.content
- }
-
- private val liveContent: LiveData<Directory.Content> by lazy {
- modifiableLiveContent.map {
- Directory.Content(
- it.directories,
- it.files,
- it.links,
- )
- }
- }
-
- override fun modifiableOpenDir(name: String): ModifiableDirectory? {
- val path = path.resolve(name)
- if (path.isDirectory(LinkOption.NOFOLLOW_LINKS)) return PathDirectory(path, pathWatcher)
- if (path.isSymbolicLink()) {
- val target = path.readSymbolicLink()
- if (target.isDirectory()) return PathDirectory(target.toRealPath(), pathWatcher)
- }
- return null
- }
-
- override fun modifiableOpenFile(name: String): ModifiableFile? {
- val path = path.resolve(name)
- if (path.isRegularFile(LinkOption.NOFOLLOW_LINKS)) return PathFile(path)
- if (path.isSymbolicLink()) {
- val target = path.readSymbolicLink()
- if (target.isRegularFile()) return PathFile(target.toRealPath())
- }
- return null
- }
-
- override fun modifiableOpenLink(name: String): ModifiableLink? {
- val path = path.resolve(name)
- return if (path.isSymbolicLink()) PathLink(path, pathWatcher) else null
- }
-
- override fun modifiableList() = makeContent(path.listDirectoryEntries())
- override fun modifiableLiveList() = modifiableLiveContent
-
- override fun createDirectory(name: String): ModifiableDirectory {
- val path = path.resolve(name)
- return PathDirectory(path.createDirectory(), pathWatcher)
- }
-
- override fun createFile(name: String): ModifiableFile {
- val path = path.resolve(name)
- return PathFile(path)
- }
-
- override fun createLink(name: String, target: Directory): ModifiableLink {
- val path = path.resolve(name)
- return PathLink(path.createSymbolicLinkPointingTo((target as PathDirectory).path), pathWatcher)
- }
-
- override fun createLink(name: String, target: File): ModifiableLink {
- val path = path.resolve(name)
- return PathLink(path.createSymbolicLinkPointingTo((target as PathFile).path), pathWatcher)
- }
-
- override fun createLink(name: String, target: String): ModifiableLink {
- val targetPath = path.resolve(target)
- val path = path.resolve(name)
- return PathLink(path.createSymbolicLinkPointingTo(targetPath), pathWatcher)
- }
-
- override fun removeDirectory(name: String): Boolean {
- val path = path.resolve(name)
- return if (path.isDirectory(LinkOption.NOFOLLOW_LINKS)) {
- path.deleteRecursively()
- true
- } else false
- }
-
- override fun removeFile(name: String): Boolean {
- val path = path.resolve(name)
- return path.isRegularFile(LinkOption.NOFOLLOW_LINKS) && path.deleteIfExists()
- }
-
- override fun removeLink(name: String): Boolean {
- val path = path.resolve(name)
- return path.isSymbolicLink() && path.deleteIfExists()
- }
-
- override val name: String
- get() = path.name
-
- override fun list(): Directory.Content {
- val modifiable = modifiableList()
- return Directory.Content(modifiable.directories, modifiable.files, modifiable.links)
- }
-
- override fun liveList() = liveContent
-
- override fun openDir(name: String) = modifiableOpenDir(name)
- override fun openFile(name: String) = modifiableOpenFile(name)
- override fun openLink(name: String) = modifiableOpenLink(name)
-
- override fun equals(other: Any?) = other is PathDirectory && other.path == path
- override fun hashCode() = path.hashCode()
- override fun toString() = path.toString()
-
- private inner class DirectoryWatcher : PathWatcher.Delegate {
- val content: LiveData<ModifiableDirectory.Content>
- get() = _content
-
- @AnyThread
- override fun update(added: List<Path>, removed: List<Path>) {
- try {
- _content.postValue(makeContent(path.listDirectoryEntries()))
- } catch (ignored: NoSuchFileException) {
- }
- }
-
- private val _content = object : MutableLiveData<ModifiableDirectory.Content>() {
- override fun onActive() {
- setup()
- }
-
- override fun onInactive() {
- clear()
- }
- }
-
- private fun setup() {
- val entries = path.listDirectoryEntries()
- pathWatcher.add(path, this)
- _content.value = makeContent(entries)
- }
-
- private fun clear() {
- pathWatcher.remove(path)
- }
- }
-
- private fun makeContent(entries: List<Path>): ModifiableDirectory.Content {
- val directories = mutableListOf<ModifiableDirectory>()
- val files = mutableListOf<ModifiableFile>()
- val links = mutableListOf<ModifiableLink>()
- entries.forEach {
- if (it.isDirectory(LinkOption.NOFOLLOW_LINKS)) {
- directories.add(PathDirectory(it, pathWatcher))
- } else if (it.isRegularFile(LinkOption.NOFOLLOW_LINKS)) {
- files.add(PathFile(it))
- } else if (it.isSymbolicLink()) {
- links.add(PathLink(it, pathWatcher))
- }
- }
- return ModifiableDirectory.Content(directories, files, links)
- }
-}
diff --git a/app/src/main/java/org/the_jk/cleversync/io/impl/PathFile.kt b/app/src/main/java/org/the_jk/cleversync/io/impl/PathFile.kt
deleted file mode 100644
index 9a8d160..0000000
--- a/app/src/main/java/org/the_jk/cleversync/io/impl/PathFile.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.the_jk.cleversync.io.impl
-
-import org.the_jk.cleversync.io.ModifiableFile
-import java.io.InputStream
-import java.io.OutputStream
-import java.nio.file.Files
-import java.nio.file.LinkOption
-import java.nio.file.Path
-import java.nio.file.StandardCopyOption
-import java.nio.file.StandardOpenOption
-import java.time.Instant
-import kotlin.io.path.exists
-import kotlin.io.path.fileSize
-import kotlin.io.path.getLastModifiedTime
-import kotlin.io.path.inputStream
-import kotlin.io.path.name
-import kotlin.io.path.outputStream
-
-internal class PathFile(internal val path: Path) : ModifiableFile {
- override fun write(): OutputStream {
- // If file doesn't exist, write to it directly.
- if (!path.exists(LinkOption.NOFOLLOW_LINKS))
- return path.outputStream(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)
-
- // Otherwise, write to temp file, only overwriting when done.
- val tmp = path.parent.resolve(".#" + path.name)
- val os = tmp.outputStream(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)
- return object : OutputStream() {
- override fun write(value: Int) {
- os.write(value)
- }
-
- override fun write(b: ByteArray) {
- os.write(b)
- }
-
- override fun write(b: ByteArray, off: Int, len: Int) {
- os.write(b, off, len)
- }
-
- override fun flush() {
- os.flush()
- }
-
- override fun close() {
- os.close()
- Files.move(tmp, path, StandardCopyOption.ATOMIC_MOVE)
- }
- }
- }
-
- override val name: String
- get() = path.name
- override val size: ULong
- get() = path.fileSize().toULong()
- override val lastModified: Instant
- get() = path.getLastModifiedTime().toInstant()
-
- override fun read(): InputStream {
- return path.inputStream(StandardOpenOption.READ)
- }
-
- override fun equals(other: Any?) = other is PathFile && other.path == path
- override fun hashCode() = path.hashCode()
- override fun toString() = path.toString()
-}
diff --git a/app/src/main/java/org/the_jk/cleversync/io/impl/PathLink.kt b/app/src/main/java/org/the_jk/cleversync/io/impl/PathLink.kt
deleted file mode 100644
index 9ae8b51..0000000
--- a/app/src/main/java/org/the_jk/cleversync/io/impl/PathLink.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.the_jk.cleversync.io.impl
-
-import org.the_jk.cleversync.io.Directory
-import org.the_jk.cleversync.io.File
-import org.the_jk.cleversync.io.Link
-import org.the_jk.cleversync.io.ModifiableLink
-import java.nio.file.Path
-import kotlin.io.path.createSymbolicLinkPointingTo
-import kotlin.io.path.deleteIfExists
-import kotlin.io.path.isDirectory
-import kotlin.io.path.isRegularFile
-import kotlin.io.path.name
-import kotlin.io.path.readSymbolicLink
-
-internal class PathLink(
- private val path: Path,
- private val pathWatcher: PathWatcher,
-) : ModifiableLink {
- override fun modifiableResolve(): ModifiableLink.ModifiableLinkTarget {
- val target = path.readSymbolicLink()
- return if (target.isDirectory()) {
- ModifiableLink.ModifiableDirectoryTarget(PathDirectory(target.toRealPath(), pathWatcher))
- } else if (target.isRegularFile()) {
- ModifiableLink.ModifiableFileTarget(PathFile(target.toRealPath()))
- } else {
- ModifiableLink.NoTarget
- }
- }
-
- override fun target(directory: Directory) {
- path.deleteIfExists()
- path.createSymbolicLinkPointingTo((directory as PathDirectory).path)
- }
-
- override fun target(file: File) {
- path.deleteIfExists()
- path.createSymbolicLinkPointingTo((file as PathFile).path)
- }
-
- override fun target(name: String) {
- path.deleteIfExists()
- path.createSymbolicLinkPointingTo(path.parent.resolve(name))
- }
-
- override val name: String
- get() = path.name
-
- override fun equals(other: Any?) = other is PathLink && other.path == path
- override fun hashCode() = path.hashCode()
- override fun toString() = path.toString()
-
- override fun resolve(): Link.LinkTarget {
- val target = path.readSymbolicLink()
- return if (target.isDirectory()) {
- Link.DirectoryTarget(PathDirectory(target.toRealPath(), pathWatcher))
- } else if (target.isRegularFile()) {
- Link.FileTarget(PathFile(target.toRealPath()))
- } else {
- Link.NoTarget
- }
- }
-}
diff --git a/app/src/main/java/org/the_jk/cleversync/io/impl/PathTree.kt b/app/src/main/java/org/the_jk/cleversync/io/impl/PathTree.kt
deleted file mode 100644
index a8a74c5..0000000
--- a/app/src/main/java/org/the_jk/cleversync/io/impl/PathTree.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.the_jk.cleversync.io.impl
-
-import android.content.res.Resources
-import org.the_jk.cleversync.R
-import org.the_jk.cleversync.io.ModifiableTree
-import java.nio.file.Path
-
-internal class PathTree(root: Path) : PathDirectory(root, PathWatcher()), ModifiableTree {
- override fun description(resources: Resources) = resources.getString(R.string.local_directory)
-}
diff --git a/app/src/main/java/org/the_jk/cleversync/io/impl/PathWatcher.kt b/app/src/main/java/org/the_jk/cleversync/io/impl/PathWatcher.kt
deleted file mode 100644
index 945019a..0000000
--- a/app/src/main/java/org/the_jk/cleversync/io/impl/PathWatcher.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.the_jk.cleversync.io.impl
-
-import androidx.annotation.GuardedBy
-import androidx.annotation.WorkerThread
-import java.nio.file.ClosedWatchServiceException
-import java.nio.file.FileSystems
-import java.nio.file.Path
-import java.nio.file.StandardWatchEventKinds
-import java.nio.file.WatchKey
-import java.nio.file.WatchService
-import java.util.concurrent.Executors
-
-internal class PathWatcher {
- private val executor = Executors.newSingleThreadExecutor()
- private var service: WatchService? = null
- private val keys = mutableMapOf<Path, WatchKey>()
- private val lock = Object()
- @GuardedBy("lock")
- private val delegates = mutableMapOf<WatchKey, Delegate>()
-
- fun add(path: Path, delegate: Delegate) {
- if (keys.isEmpty()) {
- val service = FileSystems.getDefault().newWatchService()
- executor.execute{ runner(service) }
- this.service = service
- }
- val key = path.register(service!!, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE)
- delegates[key] = delegate
- keys[path] = key
- }
-
- fun remove(path: Path) {
- val key = keys.remove(path) ?: return
- key.cancel()
- synchronized(lock) {
- delegates.remove(key)
- }
- if (keys.isEmpty()) {
- service?.close()
- service = null
- }
- }
-
- interface Delegate {
- fun update(added: List<Path>, removed: List<Path>)
- }
-
- @WorkerThread
- private fun runner(service: WatchService) {
- while (true) {
- val key: WatchKey
- try {
- key = service.take()
- } catch (ignored: InterruptedException) {
- return
- } catch (ignored: ClosedWatchServiceException) {
- return
- }
-
- val added = mutableListOf<Path>()
- val removed = mutableListOf<Path>()
- var overflow = false
-
- for (event in key.pollEvents()) {
- when (event.kind()) {
- StandardWatchEventKinds.OVERFLOW -> overflow = true
- StandardWatchEventKinds.ENTRY_CREATE -> added.add(event.context() as Path)
- StandardWatchEventKinds.ENTRY_DELETE -> removed.add(event.context() as Path)
- }
- }
-
- if (overflow || added.isNotEmpty() || removed.isNotEmpty()) {
- val delegate = synchronized(lock) {
- delegates[key]
- }
- delegate?.update(added, removed)
- }
-
- key.reset()
- }
- }
-}