aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/invalid/lena
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/invalid/lena')
-rw-r--r--app/src/main/java/invalid/lena/rsend/RsyncRunner.kt20
-rw-r--r--app/src/main/java/invalid/lena/rsend/SyncWorker.kt3
2 files changed, 19 insertions, 4 deletions
diff --git a/app/src/main/java/invalid/lena/rsend/RsyncRunner.kt b/app/src/main/java/invalid/lena/rsend/RsyncRunner.kt
index d8f8b93..c37e3ce 100644
--- a/app/src/main/java/invalid/lena/rsend/RsyncRunner.kt
+++ b/app/src/main/java/invalid/lena/rsend/RsyncRunner.kt
@@ -1,6 +1,9 @@
package invalid.lena.rsend
import android.content.Context
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.launch
// RsyncRunner builds and runs the rsync invocation for one folder, streaming
// rsync's output into the log. It uses the bundled rsync and rsh binaries and
@@ -34,14 +37,23 @@ object RsyncRunner {
private fun withSlash(p: String): String = if (p.endsWith("/")) p else "$p/"
// runFolder execs rsync for one folder, appending every output line to the
- // log, and returns rsync's exit code.
- fun runFolder(ctx: Context, remote: Remote, f: Folder, log: SyncLog): Int {
+ // log, and returns rsync's exit code. Blocks the calling thread (run it on
+ // an IO dispatcher). If the caller is cancelled (worker stopped, schedule
+ // replaced, constraints lost) the watchdog kills rsync rather than leave it
+ // running detached; killing it also closes its pipes, which unblocks the
+ // log reader below. destroy() on an already-exited process is a no-op.
+ suspend fun runFolder(ctx: Context, remote: Remote, f: Folder, log: SyncLog): Int = coroutineScope {
val cmd = listOf(Native.rsync(ctx).absolutePath) + args(Native.rsh(ctx).absolutePath, remote, f)
log.line("rsync ${cmd.drop(1).joinToString(" ")}")
val pb = ProcessBuilder(cmd).redirectErrorStream(true)
pb.environment().putAll(Keys.env(ctx, remote.port))
val p = pb.start()
- p.inputStream.bufferedReader().forEachLine { log.line(it) }
- return p.waitFor()
+ val watchdog = launch { try { awaitCancellation() } finally { p.destroy() } }
+ try {
+ p.inputStream.bufferedReader().forEachLine { log.line(it) }
+ p.waitFor()
+ } finally {
+ watchdog.cancel()
+ }
}
}
diff --git a/app/src/main/java/invalid/lena/rsend/SyncWorker.kt b/app/src/main/java/invalid/lena/rsend/SyncWorker.kt
index a70a3e6..1b14673 100644
--- a/app/src/main/java/invalid/lena/rsend/SyncWorker.kt
+++ b/app/src/main/java/invalid/lena/rsend/SyncWorker.kt
@@ -61,6 +61,9 @@ class SyncWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx,
1
} else try {
RsyncRunner.runFolder(ctx, cfg.remote, f, log)
+ } catch (e: CancellationException) {
+ log.line("cancelled")
+ throw e
} catch (e: Exception) {
log.line("error: ${e.message}")
1