aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPacien TRAN-GIRARD2017-07-09 20:20:14 +0200
committerPacien TRAN-GIRARD2017-07-09 20:21:15 +0200
commit2c5673b187233a30a0dd284bc37436fc30596c66 (patch)
tree8d6297648124a639878392c95e266ec91cfe45cd
parent5c52c7fbc522e7d11141291d5650bb53cd1fa509 (diff)
downloadtincapp-2c5673b187233a30a0dd284bc37436fc30596c66.tar.gz
Make tincctl calls properly async
-rw-r--r--app/build.gradle2
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/StatusActivity.kt36
-rw-r--r--app/src/main/java/org/pacien/tincapp/commands/Executor.kt26
-rw-r--r--app/src/main/java/org/pacien/tincapp/commands/Tinc.kt30
-rw-r--r--app/src/main/java/org/pacien/tincapp/commands/Tincd.kt2
5 files changed, 61 insertions, 35 deletions
diff --git a/app/build.gradle b/app/build.gradle
index c25ab83..2d31df9 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -51,6 +51,8 @@ dependencies {
51 exclude group: 'commons-logging', module: 'commons-logging' 51 exclude group: 'commons-logging', module: 'commons-logging'
52 } 52 }
53 53
54 compile 'net.sourceforge.streamsupport:streamsupport-cfuture:1.5.5'
55
54 compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 56 compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
55} 57}
56 58
diff --git a/app/src/main/java/org/pacien/tincapp/activities/StatusActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/StatusActivity.kt
index 44f4f89..fb6ab73 100644
--- a/app/src/main/java/org/pacien/tincapp/activities/StatusActivity.kt
+++ b/app/src/main/java/org/pacien/tincapp/activities/StatusActivity.kt
@@ -10,6 +10,7 @@ import android.view.View
10import android.widget.AdapterView 10import android.widget.AdapterView
11import android.widget.ArrayAdapter 11import android.widget.ArrayAdapter
12import android.widget.TextView 12import android.widget.TextView
13import java8.util.concurrent.CompletableFuture
13import kotlinx.android.synthetic.main.base.* 14import kotlinx.android.synthetic.main.base.*
14import kotlinx.android.synthetic.main.dialog_text_monopsace.view.* 15import kotlinx.android.synthetic.main.dialog_text_monopsace.view.*
15import kotlinx.android.synthetic.main.fragment_network_status_header.* 16import kotlinx.android.synthetic.main.fragment_network_status_header.*
@@ -78,24 +79,28 @@ class StatusActivity : BaseActivity(), AdapterView.OnItemClickListener, SwipeRef
78 } 79 }
79 80
80 override fun onRefresh() { 81 override fun onRefresh() {
81 val nodes = getNodeNames() 82 getNodeNames().thenAccept {
82 runOnUiThread { 83 runOnUiThread {
83 nodeListAdapter?.setElements(nodes) 84 nodeListAdapter?.setElements(it)
84 node_list_wrapper.isRefreshing = false 85 node_list_wrapper.isRefreshing = false
85 if (!TincVpnService.isConnected()) openStartActivity() 86 if (!TincVpnService.isConnected()) openStartActivity()
87 }
86 } 88 }
87 } 89 }
88 90
89 override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { 91 override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
90 val nodeName = (view as TextView).text.toString() 92 val nodeName = (view as TextView).text.toString()
91 val dialogTextView = layoutInflater.inflate(R.layout.dialog_text_monopsace, main_content, false) 93 val dialogTextView = layoutInflater.inflate(R.layout.dialog_text_monopsace, main_content, false)
92 dialogTextView.dialog_text_monospace.text = Tinc.info(TincVpnService.getCurrentNetName()!!, nodeName) 94 Tinc.info(TincVpnService.getCurrentNetName()!!, nodeName).thenAccept {
93 95 runOnUiThread {
94 AlertDialog.Builder(this) 96 dialogTextView.dialog_text_monospace.text = it
95 .setTitle(R.string.title_node_info) 97 AlertDialog.Builder(this)
96 .setView(dialogTextView) 98 .setTitle(R.string.title_node_info)
97 .setPositiveButton(R.string.action_close) { _, _ -> /* nop */ } 99 .setView(dialogTextView)
98 .show() 100 .setPositiveButton(R.string.action_close) { _, _ -> /* nop */ }
101 .show()
102 }
103 }
99 } 104 }
100 105
101 fun writeNetworkInfo(cfg: VpnInterfaceConfiguration) { 106 fun writeNetworkInfo(cfg: VpnInterfaceConfiguration) {
@@ -129,9 +134,10 @@ class StatusActivity : BaseActivity(), AdapterView.OnItemClickListener, SwipeRef
129 companion object { 134 companion object {
130 private val REFRESH_RATE = 5000L 135 private val REFRESH_RATE = 5000L
131 136
132 fun getNodeNames() = 137 fun getNodeNames(): CompletableFuture<List<String>> = when (TincVpnService.isConnected()) {
133 if (TincVpnService.isConnected()) Tinc.dumpNodes(TincVpnService.getCurrentNetName()!!).map { it.substringBefore(" ") } 138 true -> Tinc.dumpNodes(TincVpnService.getCurrentNetName()!!).thenApply<List<String>> { it.map { it.substringBefore(" ") } }
134 else emptyList() 139 false -> CompletableFuture.supplyAsync<List<String>> { emptyList() }
140 }
135 } 141 }
136 142
137} 143}
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 c93de64..eccd2f9 100644
--- a/app/src/main/java/org/pacien/tincapp/commands/Executor.kt
+++ b/app/src/main/java/org/pacien/tincapp/commands/Executor.kt
@@ -1,7 +1,9 @@
1package org.pacien.tincapp.commands 1package org.pacien.tincapp.commands
2 2
3import java8.util.concurrent.CompletableFuture
3import java.io.BufferedReader 4import java.io.BufferedReader
4import java.io.IOException 5import java.io.IOException
6import java.io.InputStream
5import java.io.InputStreamReader 7import java.io.InputStreamReader
6 8
7/** 9/**
@@ -9,6 +11,8 @@ import java.io.InputStreamReader
9 */ 11 */
10internal object Executor { 12internal object Executor {
11 13
14 class CommandExecutionException(msg: String) : Exception(msg)
15
12 init { 16 init {
13 System.loadLibrary("exec") 17 System.loadLibrary("exec")
14 } 18 }
@@ -18,17 +22,23 @@ internal object Executor {
18 */ 22 */
19 private external fun forkExec(argcv: Array<String>): Int 23 private external fun forkExec(argcv: Array<String>): Int
20 24
21 @Throws(IOException::class) 25 private fun read(stream: InputStream) = BufferedReader(InputStreamReader(stream)).readLines()
26
22 fun forkExec(cmd: Command) { 27 fun forkExec(cmd: Command) {
23 if (forkExec(cmd.asArray()) == -1) 28 if (forkExec(cmd.asArray()) == -1) throw CommandExecutionException("Could not fork child process.")
24 throw IOException()
25 } 29 }
26 30
27 @Throws(IOException::class) 31 fun call(cmd: Command): CompletableFuture<List<String>> {
28 fun call(cmd: Command): List<String> { 32 val proc = try {
29 val proc = ProcessBuilder(cmd.asList()).start() 33 ProcessBuilder(cmd.asList()).start()
30 val outputReader = BufferedReader(InputStreamReader(proc.inputStream)) 34 } catch (e: IOException) {
31 return outputReader.readLines() 35 throw CommandExecutionException(e.message ?: "Could not start process.")
36 }
37
38 return CompletableFuture.supplyAsync<List<String>> {
39 if (proc.waitFor() == 0) read(proc.inputStream)
40 else throw CommandExecutionException(read(proc.errorStream).lastOrNull() ?: "Non-zero exit status.")
41 }
32 } 42 }
33 43
34} 44}
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 9b57233..120525d 100644
--- a/app/src/main/java/org/pacien/tincapp/commands/Tinc.kt
+++ b/app/src/main/java/org/pacien/tincapp/commands/Tinc.kt
@@ -1,7 +1,7 @@
1package org.pacien.tincapp.commands 1package org.pacien.tincapp.commands
2 2
3import java8.util.concurrent.CompletableFuture
3import org.pacien.tincapp.context.AppPaths 4import org.pacien.tincapp.context.AppPaths
4import java.io.IOException
5 5
6/** 6/**
7 * @author pacien 7 * @author pacien
@@ -13,19 +13,29 @@ object Tinc {
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 @Throws(IOException::class) 16 fun stop(netName: String): CompletableFuture<Unit> =
17 fun stop(netName: String) { 17 Executor.call(newCommand(netName).withArguments("stop"))
18 Executor.call(newCommand(netName).withArguments("stop")) 18 .thenApply { }
19 }
20 19
21 @Throws(IOException::class) 20 fun dumpNodes(netName: String, reachable: Boolean = false): CompletableFuture<List<String>> =
22 fun dumpNodes(netName: String, reachable: Boolean = false): List<String> =
23 Executor.call( 21 Executor.call(
24 if (reachable) newCommand(netName).withArguments("dump", "reachable", "nodes") 22 if (reachable) newCommand(netName).withArguments("dump", "reachable", "nodes")
25 else newCommand(netName).withArguments("dump", "nodes")) 23 else newCommand(netName).withArguments("dump", "nodes"))
26 24
27 @Throws(IOException::class) 25 fun info(netName: String, node: String): CompletableFuture<String> =
28 fun info(netName: String, node: String): String = 26 Executor.call(newCommand(netName).withArguments("info", node))
29 Executor.call(newCommand(netName).withArguments("info", node)).joinToString("\n") 27 .thenApply<String> { it.joinToString("\n") }
28
29 fun init(netName: String): CompletableFuture<String> =
30 Executor.call(Command(AppPaths.tinc().absolutePath)
31 .withOption("config", AppPaths.confDir(netName).absolutePath)
32 .withArguments("init", netName))
33 .thenApply<String> { it.joinToString("\n") }
34
35 fun join(netName: String, invitationUrl: String): CompletableFuture<String> =
36 Executor.call(Command(AppPaths.tinc().absolutePath)
37 .withOption("config", AppPaths.confDir(netName).absolutePath)
38 .withArguments("join", invitationUrl))
39 .thenApply<String> { it.joinToString("\n") }
30 40
31} 41}
diff --git a/app/src/main/java/org/pacien/tincapp/commands/Tincd.kt b/app/src/main/java/org/pacien/tincapp/commands/Tincd.kt
index 19ebfbd..db113cc 100644
--- a/app/src/main/java/org/pacien/tincapp/commands/Tincd.kt
+++ b/app/src/main/java/org/pacien/tincapp/commands/Tincd.kt
@@ -1,14 +1,12 @@