diff options
Diffstat (limited to 'app/src/main/java/org/pacien/tincapp/commands')
5 files changed, 116 insertions, 116 deletions
diff --git a/app/src/main/java/org/pacien/tincapp/commands/Command.kt b/app/src/main/java/org/pacien/tincapp/commands/Command.kt index 6eab66b..cb95619 100644 --- a/app/src/main/java/org/pacien/tincapp/commands/Command.kt +++ b/app/src/main/java/org/pacien/tincapp/commands/Command.kt | |||
@@ -7,25 +7,25 @@ import java.util.* | |||
7 | */ | 7 | */ |
8 | internal class Command(private val cmd: String) { | 8 | internal class Command(private val cmd: String) { |
9 | 9 | ||
10 | private data class Option(val key: String, val value: String?) { | 10 | private data class Option(val key: String, val value: String?) { |
11 | fun toCommandLineOption(): String = if (value != null) "--$key=$value" else "--$key" | 11 | fun toCommandLineOption(): String = if (value != null) "--$key=$value" else "--$key" |
12 | } | 12 | } |
13 | 13 | ||
14 | private val opts: MutableList<Option> = LinkedList() | 14 | private val opts: MutableList<Option> = LinkedList() |
15 | private val args: MutableList<String> = LinkedList() | 15 | private val args: MutableList<String> = LinkedList() |
16 | 16 | ||
17 | fun withOption(key: String, value: String? = null): Command { | 17 | fun withOption(key: String, value: String? = null): Command { |
18 | this.opts.add(Option(key, value)) | 18 | this.opts.add(Option(key, value)) |
19 | return this | 19 | return this |
20 | } | 20 | } |
21 | 21 | ||
22 | fun withArguments(vararg args: String): Command { | 22 | fun withArguments(vararg args: String): Command { |
23 | this.args.addAll(Arrays.asList(*args)) | 23 | this.args.addAll(Arrays.asList(*args)) |
24 | return this | 24 | return this |
25 | } | 25 | } |
26 | 26 | ||
27 | fun asList(): List<String> = listOf(cmd) + opts.map { it.toCommandLineOption() } + args | 27 | fun asList(): List<String> = listOf(cmd) + opts.map { it.toCommandLineOption() } + args |
28 | 28 | ||
29 | fun asArray(): Array<String> = this.asList().toTypedArray() | 29 | fun asArray(): Array<String> = this.asList().toTypedArray() |
30 | 30 | ||
31 | } | 31 | } |
diff --git a/app/src/main/java/org/pacien/tincapp/commands/Executor.kt b/app/src/main/java/org/pacien/tincapp/commands/Executor.kt index 38c2cb5..eace2e7 100644 --- a/app/src/main/java/org/pacien/tincapp/commands/Executor.kt +++ b/app/src/main/java/org/pacien/tincapp/commands/Executor.kt | |||
@@ -13,37 +13,37 @@ import java.io.InputStreamReader | |||
13 | */ | 13 | */ |
14 | internal object Executor { | 14 | internal object Executor { |
15 | 15 | ||
16 | class CommandExecutionException(msg: String) : Exception(msg) | 16 | class CommandExecutionException(msg: String) : Exception(msg) |
17 | 17 | ||
18 | init { | 18 | init { |
19 | System.loadLibrary("exec") | 19 | System.loadLibrary("exec") |
20 | } | 20 | } |
21 | |||
22 | /** | ||
23 | * @return -1 on error, forked child PID otherwise | ||
24 | */ | ||
25 | private external fun forkExec(argcv: Array<String>): Int | ||
21 | 26 | ||
22 | /** | 27 | private fun read(stream: InputStream) = BufferedReader(InputStreamReader(stream)).readLines() |
23 | * @return -1 on error, forked child PID otherwise | ||
24 | */ | ||
25 | private external fun forkExec(argcv: Array<String>): Int | ||
26 | 28 | ||
27 | private fun read(stream: InputStream) = BufferedReader(InputStreamReader(stream)).readLines() | 29 | fun forkExec(cmd: Command) { |
30 | if (forkExec(cmd.asArray()) == -1) throw CommandExecutionException("Could not fork child process.") | ||
31 | } | ||
28 | 32 | ||
29 | fun forkExec(cmd: Command) { | 33 | fun call(cmd: Command): CompletableFuture<List<String>> { |
30 | if (forkExec(cmd.asArray()) == -1) throw CommandExecutionException("Could not fork child process.") | 34 | val proc = try { |
35 | ProcessBuilder(cmd.asList()).start() | ||
36 | } catch (e: IOException) { | ||
37 | throw CommandExecutionException(e.message ?: "Could not start process.") | ||
31 | } | 38 | } |
32 | 39 | ||
33 | fun call(cmd: Command): CompletableFuture<List<String>> { | 40 | return supplyAsyncTask<List<String>> { |
34 | val proc = try { | 41 | if (proc.waitFor() == 0) read(proc.inputStream) |
35 | ProcessBuilder(cmd.asList()).start() | 42 | else throw CommandExecutionException(read(proc.errorStream).lastOrNull() ?: "Non-zero exit status.") |
36 | } catch (e: IOException) { | ||
37 | throw CommandExecutionException(e.message ?: "Could not start process.") | ||
38 | } | ||
39 | |||
40 | return supplyAsyncTask<List<String>> { | ||
41 | if (proc.waitFor() == 0) read(proc.inputStream) | ||
42 | else throw CommandExecutionException(read(proc.errorStream).lastOrNull() ?: "Non-zero exit status.") | ||
43 | } | ||
44 | } | 43 | } |
44 | } | ||
45 | 45 | ||
46 | fun runAsyncTask(r: () -> Unit) = CompletableFuture.runAsync(Runnable(r), AsyncTask.THREAD_POOL_EXECUTOR)!! | 46 | fun runAsyncTask(r: () -> Unit) = CompletableFuture.runAsync(Runnable(r), AsyncTask.THREAD_POOL_EXECUTOR)!! |
47 | fun <U> supplyAsyncTask(s: () -> U) = CompletableFuture.supplyAsync(Supplier(s), AsyncTask.THREAD_POOL_EXECUTOR)!! | 47 | fun <U> supplyAsyncTask(s: () -> U) = CompletableFuture.supplyAsync(Supplier(s), AsyncTask.THREAD_POOL_EXECUTOR)!! |
48 | 48 | ||
49 | } | 49 | } |
diff --git a/app/src/main/java/org/pacien/tincapp/commands/Tinc.kt b/app/src/main/java/org/pacien/tincapp/commands/Tinc.kt index 6acd4f2..0b1240a 100644 --- a/app/src/main/java/org/pacien/tincapp/commands/Tinc.kt +++ b/app/src/main/java/org/pacien/tincapp/commands/Tinc.kt | |||
@@ -8,40 +8,40 @@ import org.pacien.tincapp.context.AppPaths | |||
8 | */ | 8 | */ |
9 | object Tinc { | 9 | object Tinc { |
10 | 10 | ||
11 | private fun newCommand(netName: String): Command = | 11 | private fun newCommand(netName: String): Command = |
12 | Command(AppPaths.tinc().absolutePath) | 12 | Command(AppPaths.tinc().absolutePath) |
13 | .withOption("config", AppPaths.confDir(netName).absolutePath) | 13 | .withOption("config", AppPaths.confDir(netName).absolutePath) |
14 | .withOption("pidfile", AppPaths.pidFile(netName).absolutePath) | 14 | .withOption("pidfile", AppPaths.pidFile(netName).absolutePath) |
15 | 15 | ||
16 | fun stop(netName: String): CompletableFuture<Unit> = | 16 | fun stop(netName: String): CompletableFuture<Unit> = |
17 | Executor.call(newCommand(netName).withArguments("stop")) | 17 | Executor.call(newCommand(netName).withArguments("stop")) |
18 | .thenApply { } | 18 | .thenApply { } |
19 | 19 | ||
20 | fun dumpNodes(netName: String, reachable: Boolean = false): CompletableFuture<List<String>> = | 20 | fun dumpNodes(netName: String, reachable: Boolean = false): CompletableFuture<List<String>> = |
21 | Executor.call( | 21 | Executor.call( |
22 | if (reachable) newCommand(netName).withArguments("dump", "reachable", "nodes") | 22 | if (reachable) newCommand(netName).withArguments("dump", "reachable", "nodes") |
23 | else newCommand(netName).withArguments("dump", "nodes")) | 23 | else newCommand(netName).withArguments("dump", "nodes")) |
24 | 24 | ||
25 | fun info(netName: String, node: String): CompletableFuture<String> = | 25 | fun info(netName: String, node: String): CompletableFuture<String> = |
26 | Executor.call(newCommand(netName).withArguments("info", node)) | 26 | Executor.call(newCommand(netName).withArguments("info", node)) |
27 | .thenApply<String> { it.joinToString("\n") } | 27 | .thenApply<String> { it.joinToString("\n") } |
28 | 28 | ||
29 | fun init(netName: String, nodeName: String): CompletableFuture<String> = | 29 | fun init(netName: String, nodeName: String): CompletableFuture<String> = |
30 | if (netName.isBlank()) | 30 | if (netName.isBlank()) |
31 | CompletableFuture.failedFuture(IllegalArgumentException("Network name cannot be blank.")) | 31 | CompletableFuture.failedFuture(IllegalArgumentException("Network name cannot be blank.")) |
32 | else | 32 | else |
33 | Executor.call(Command(AppPaths.tinc().absolutePath) | 33 | Executor.call(Command(AppPaths.tinc().absolutePath) |
34 | .withOption("config", AppPaths.confDir(netName).absolutePath) | 34 | .withOption("config", AppPaths.confDir(netName).absolutePath) |
35 | .withArguments("init", nodeName)) | 35 | .withArguments("init", nodeName)) |
36 | .thenApply<String> { it.joinToString("\n") } | 36 | .thenApply<String> { it.joinToString("\n") } |
37 | 37 | ||
38 | fun join(netName: String, invitationUrl: String): CompletableFuture<String> = | 38 | fun join(netName: String, invitationUrl: String): CompletableFuture<String> = |
39 | if (netName.isBlank()) | 39 | if (netName.isBlank()) |
40 | CompletableFuture.failedFuture(IllegalArgumentException("Network name cannot be blank.")) | 40 | CompletableFuture.failedFuture(IllegalArgumentException("Network name cannot be blank.")) |
41 | else | 41 | else |
42 | Executor.call(Command(AppPaths.tinc().absolutePath) | 42 | Executor.call(Command(AppPaths.tinc().absolutePath) |
43 | .withOption("config", AppPaths.confDir(netName).absolutePath) | 43 | .withOption("config", AppPaths.confDir(netName).absolutePath) |
44 | .withArguments("join", invitationUrl)) | 44 | .withArguments("join", invitationUrl)) |
45 | .thenApply<String> { it.joinToString("\n") } | 45 | .thenApply<String> { it.joinToString("\n") } |
46 | 46 | ||
47 | } | 47 | } |
diff --git a/app/src/main/java/org/pacien/tincapp/commands/TincApp.kt b/app/src/main/java/org/pacien/tincapp/commands/TincApp.kt index b564b6a..11adb69 100644 --- a/app/src/main/java/org/pacien/tincapp/commands/TincApp.kt +++ b/app/src/main/java/org/pacien/tincapp/commands/TincApp.kt | |||
@@ -15,39 +15,39 @@ import java.io.FileNotFoundException | |||
15 | */ | 15 | */ |
16 | object TincApp { | 16 | object TincApp { |
17 | 17 | ||
18 | private val SCRIPT_SUFFIXES = listOf("-up", "-down", "-created", "-accepted") | 18 | private val SCRIPT_SUFFIXES = listOf("-up", "-down", "-created", "-accepted") |
19 | private val STATIC_SCRIPTS = listOf("tinc", "host", "subnet", "invitation").flatMap { s -> SCRIPT_SUFFIXES.map { s + it } } | 19 | private val STATIC_SCRIPTS = listOf("tinc", "host", "subnet", "invitation").flatMap { s -> SCRIPT_SUFFIXES.map { s + it } } |
20 | |||
21 | private fun listScripts(netName: String) = AppPaths.confDir(netName).listFiles { f -> f.name in STATIC_SCRIPTS } + | ||
22 | AppPaths.hostsDir(netName).listFiles { f -> SCRIPT_SUFFIXES.any { f.name.endsWith(it) } } | ||
23 | |||
24 | fun listPrivateKeys(netName: String) = try { | ||
25 | TincConfiguration.fromTincConfiguration(AppPaths.existing(AppPaths.tincConfFile(netName))).let { | ||
26 | listOf( | ||
27 | it.privateKeyFile ?: AppPaths.defaultRsaPrivateKeyFile(netName), | ||
28 |