aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorHarsh Shandilya <me@msfjarvis.dev>2020-03-31 18:41:31 +0530
committerHarsh Shandilya <me@msfjarvis.dev>2020-04-10 00:09:24 +0530
commit058e3e55f5b8aa5ac04ddb9abcc061b93e4df2d8 (patch)
treecdd56d5052095eee3a4c9082262ed63cb34dd90e
parentui: make TunnelManager init asynchronous (diff)
downloadwireguard-android-058e3e55f5b8aa5ac04ddb9abcc061b93e4df2d8.tar.xz
wireguard-android-058e3e55f5b8aa5ac04ddb9abcc061b93e4df2d8.zip
ZipExporterPreference: switch to coroutines
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
-rw-r--r--ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt9
-rw-r--r--ui/src/main/java/com/wireguard/android/model/TunnelManager.kt15
-rw-r--r--ui/src/main/java/com/wireguard/android/preference/ZipExporterPreference.kt65
3 files changed, 60 insertions, 29 deletions
diff --git a/ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt b/ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt
index e7134c51..969f6512 100644
--- a/ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt
+++ b/ui/src/main/java/com/wireguard/android/model/ObservableTunnel.kt
@@ -14,6 +14,8 @@ import com.wireguard.android.util.ExceptionLoggers
import com.wireguard.config.Config
import java9.util.concurrent.CompletableFuture
import java9.util.concurrent.CompletionStage
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.Deferred
/**
* Encapsulates the volatile and nonvolatile state of a WireGuard tunnel.
@@ -78,6 +80,13 @@ class ObservableTunnel internal constructor(
else
CompletableFuture.completedFuture(config)
+ suspend fun getConfigAsync(): Deferred<Config> {
+ return if (config == null)
+ manager.getTunnelConfigAsync(this)
+ else
+ CompletableDeferred<Config>().apply { complete(config!!) }
+ }
+
fun setConfigAsync(config: Config): CompletionStage<Config> = if (config != this.config)
manager.setTunnelConfig(this, config)
else
diff --git a/ui/src/main/java/com/wireguard/android/model/TunnelManager.kt b/ui/src/main/java/com/wireguard/android/model/TunnelManager.kt
index 5d2afa76..a201d26f 100644
--- a/ui/src/main/java/com/wireguard/android/model/TunnelManager.kt
+++ b/ui/src/main/java/com/wireguard/android/model/TunnelManager.kt
@@ -26,6 +26,8 @@ import com.wireguard.android.util.ExceptionLoggers
import com.wireguard.config.Config
import java9.util.concurrent.CompletableFuture
import java9.util.concurrent.CompletionStage
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.withContext
@@ -36,6 +38,7 @@ import java.util.ArrayList
*/
class TunnelManager(private val configStore: ConfigStore) : BaseObservable() {
val tunnels = CompletableFuture<ObservableSortedKeyedArrayList<String, ObservableTunnel>>()
+ private val tunnelsAsync = CompletableDeferred<ObservableSortedKeyedArrayList<String, ObservableTunnel>>()
private val context: Context = get()
private val delayedLoadRestoreTunnels = ArrayList<CompletableFuture<Void>>()
private val tunnelMap: ObservableSortedKeyedArrayList<String, ObservableTunnel> = ObservableSortedKeyedArrayList(TunnelComparator)
@@ -95,9 +98,20 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() {
getSharedPreferences().edit().remove(KEY_LAST_USED_TUNNEL).commit()
}
+ suspend fun getTunnelsAsync() = tunnelsAsync.await()
+
fun getTunnelConfig(tunnel: ObservableTunnel): CompletionStage<Config> = getAsyncWorker()
.supplyAsync { configStore.load(tunnel.name) }.thenApply(tunnel::onConfigChanged)
+ suspend fun getTunnelConfigAsync(tunnel: ObservableTunnel): Deferred<Config> = withContext(Dispatchers.IO) {
+ val deferred = CompletableDeferred<Config>()
+ configStore.load(tunnel.name).also {
+ tunnel.onConfigChanged(it)
+ deferred.complete(it)
+ }
+ deferred
+ }
+
suspend fun onCreate() = withContext(Dispatchers.IO) {
val storedConfigs = async { configStore.enumerate() }
val runningTunnels = async { getBackend().runningTunnelNames }
@@ -125,6 +139,7 @@ class TunnelManager(private val configStore: ConfigStore) : BaseObservable() {
}
}
tunnels.complete(tunnelMap)
+ tunnelsAsync.complete(tunnelMap)
}
fun refreshTunnelStates() {
diff --git a/ui/src/main/java/com/wireguard/android/preference/ZipExporterPreference.kt b/ui/src/main/java/com/wireguard/android/preference/ZipExporterPreference.kt
index cdd25134..e3529e26 100644
--- a/ui/src/main/java/com/wireguard/android/preference/ZipExporterPreference.kt
+++ b/ui/src/main/java/com/wireguard/android/preference/ZipExporterPreference.kt
@@ -18,48 +18,55 @@ import com.wireguard.android.util.BiometricAuthenticator
import com.wireguard.android.util.DownloadsFileSaver
import com.wireguard.android.util.ErrorMessages
import com.wireguard.android.util.FragmentUtils
-import java9.util.concurrent.CompletableFuture
-import java.nio.charset.StandardCharsets
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.supervisorScope
+import kotlinx.coroutines.withContext
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
/**
* Preference implementing a button that asynchronously exports config zips.
*/
-class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
+@ExperimentalCoroutinesApi
+class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs), CoroutineScope {
private var exportedFilePath: String? = null
+ override val coroutineContext
+ get() = Job() + Dispatchers.Default
- private fun exportZip() {
- Application.getTunnelManager().tunnels.thenAccept(this::exportZip)
- }
-
- private fun exportZip(tunnels: List<ObservableTunnel>) {
- val futureConfigs = tunnels.map { it.configAsync.toCompletableFuture() }.toTypedArray()
- if (futureConfigs.isEmpty()) {
+ private suspend fun exportZip(tunnels: List<ObservableTunnel>) = supervisorScope {
+ val asyncConfigs = tunnels.map { it.getConfigAsync() }.toList()
+ if (asyncConfigs.isEmpty()) {
exportZipComplete(null, IllegalArgumentException(
context.getString(R.string.no_tunnels_error)))
- return
+ return@supervisorScope
}
- CompletableFuture.allOf(*futureConfigs)
- .whenComplete { _, exception ->
- Application.getAsyncWorker().supplyAsync {
- if (exception != null) throw exception
- val outputFile = DownloadsFileSaver.save(context, "wireguard-export.zip", "application/zip", true)
- try {
- ZipOutputStream(outputFile.outputStream).use { zip ->
- for (i in futureConfigs.indices) {
- zip.putNextEntry(ZipEntry(tunnels[i].name + ".conf"))
- zip.write(futureConfigs[i].getNow(null)!!.toWgQuickString().toByteArray(StandardCharsets.UTF_8))
- }
- zip.closeEntry()
+ try {
+ asyncConfigs.awaitAll().let {
+ val outputFile = DownloadsFileSaver.save(context, "wireguard-export.zip", "application/zip", true)
+ try {
+ withContext(Dispatchers.IO) {
+ ZipOutputStream(outputFile.outputStream).use { zip ->
+ it.forEachIndexed { i, config ->
+ zip.putNextEntry(ZipEntry("${tunnels[i].name}.conf"))
+ zip.write(config.toWgQuickString().toByteArray(Charsets.UTF_8))
}
- } catch (e: Exception) {
- outputFile.delete()
- throw e
+ zip.closeEntry()
}
- outputFile.fileName
- }.whenComplete(this::exportZipComplete)
+ }
+ } catch (e: Exception) {
+ outputFile.delete()
+ throw e
}
+ withContext(Dispatchers.Main) { exportZipComplete(outputFile.fileName, null) }
+ }
+ } catch (e: Exception) {
+ withContext(Dispatchers.Main) { exportZipComplete(null, e) }
+ }
}
private fun exportZipComplete(filePath: String?, throwable: Throwable?) {
@@ -91,7 +98,7 @@ class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference
prefActivity.ensurePermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { _, grantResults ->
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
isEnabled = false
- exportZip()
+ launch { exportZip(Application.getTunnelManager().getTunnelsAsync()) }
}
}
}