diff options
Diffstat (limited to 'app/src/main/java')
4 files changed, 59 insertions, 35 deletions
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 | |||
10 | import android.widget.AdapterView | 10 | import android.widget.AdapterView |
11 | import android.widget.ArrayAdapter | 11 | import android.widget.ArrayAdapter |
12 | import android.widget.TextView | 12 | import android.widget.TextView |
13 | import java8.util.concurrent.CompletableFuture | ||
13 | import kotlinx.android.synthetic.main.base.* | 14 | import kotlinx.android.synthetic.main.base.* |
14 | import kotlinx.android.synthetic.main.dialog_text_monopsace.view.* | 15 | import kotlinx.android.synthetic.main.dialog_text_monopsace.view.* |
15 | import kotlinx.android.synthetic.main.fragment_network_status_header.* | 16 | import 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 @@ | |||
1 | package org.pacien.tincapp.commands | 1 | package org.pacien.tincapp.commands |
2 | 2 | ||
3 | import java8.util.concurrent.CompletableFuture | ||
3 | import java.io.BufferedReader | 4 | import java.io.BufferedReader |
4 | import java.io.IOException | 5 | import java.io.IOException |
6 | import java.io.InputStream | ||
5 | import java.io.InputStreamReader | 7 | import java.io.InputStreamReader |
6 | 8 | ||
7 | /** | 9 | /** |
@@ -9,6 +11,8 @@ import java.io.InputStreamReader | |||
9 | */ | 11 | */ |
10 | internal object Executor { | 12 | internal 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 @@ | |||
1 | package org.pacien.tincapp.commands | 1 | package org.pacien.tincapp.commands |
2 | 2 | ||
3 | import java8.util.concurrent.CompletableFuture | ||
3 | import org.pacien.tincapp.context.AppPaths | 4 | import org.pacien.tincapp.context.AppPaths |
4 | import 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 @@ | |||
1 | package org.pacien.tincapp.commands | 1 | package org.pacien.tincapp.commands |
2 | 2 | ||
3 | import org.pacien.tincapp.context.AppPaths | 3 | import org.pacien.tincapp.context.AppPaths |
4 | import java.io.IOException | ||
5 | 4 | ||
6 | /** | 5 | /** |
7 | * @author pacien | 6 | * @author pacien |
8 | */ | 7 | */ |
9 | object Tincd { | 8 | object Tincd { |
10 |