coroutines: convert the rest

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld
2020-09-15 12:30:15 +02:00
parent 2fc0bb1a03
commit bab70ab51e
23 changed files with 571 additions and 534 deletions
@@ -8,22 +8,28 @@ import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.util.AttributeSet
import android.util.Log
import androidx.preference.Preference
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.activity.SettingsActivity
import com.wireguard.android.backend.Tunnel
import com.wireguard.android.backend.WgQuickBackend
import java9.util.concurrent.CompletableFuture
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.system.exitProcess
class KernelModuleDisablerPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
private var state = State.UNKNOWN
init {
isVisible = false
Application.getBackendAsync().thenAccept { backend ->
setState(if (backend is WgQuickBackend) State.ENABLED else State.DISABLED)
GlobalScope.launch(Dispatchers.Main.immediate) {
setState(if (Application.getBackend() is WgQuickBackend) State.ENABLED else State.DISABLED)
}
}
@@ -40,17 +46,21 @@ class KernelModuleDisablerPreference(context: Context, attrs: AttributeSet?) : P
setState(State.DISABLING)
Application.getSharedPreferences().edit().putBoolean("disable_kernel_module", true).commit()
}
Application.getAsyncWorker().runAsync {
Application.getTunnelManager().tunnels.thenApply { observableTunnels ->
val downings = observableTunnels.map { it.setStateAsync(Tunnel.State.DOWN).toCompletableFuture() }.toTypedArray()
CompletableFuture.allOf(*downings).thenRun {
GlobalScope.launch(Dispatchers.Main.immediate) {
val observableTunnels = Application.getTunnelManager().getTunnels()
val downings = observableTunnels.map { async(SupervisorJob()) { it.setStateAsync(Tunnel.State.DOWN) } }
try {
downings.awaitAll()
withContext(Dispatchers.IO) {
val restartIntent = Intent(context, SettingsActivity::class.java)
restartIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
restartIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
Application.get().startActivity(restartIntent)
exitProcess(0)
}
}.join()
} catch (e: Throwable) {
Log.println(Log.ERROR, TAG, Log.getStackTraceString(e))
}
}
}
@@ -69,4 +79,8 @@ class KernelModuleDisablerPreference(context: Context, attrs: AttributeSet?) : P
ENABLING(R.string.module_disabler_disabled_title, R.string.success_application_will_restart, false, true),
DISABLING(R.string.module_disabler_enabled_title, R.string.success_application_will_restart, false, true);
}
companion object {
private const val TAG = "WireGuard/KernelModuleDisablerPreference"
}
}
@@ -15,16 +15,14 @@ import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.activity.SettingsActivity
import com.wireguard.android.util.ErrorMessages
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.system.exitProcess
class ModuleDownloaderPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
private var state = State.INITIAL
private val coroutineScope = CoroutineScope(Dispatchers.Main)
override fun getSummary() = context.getString(state.messageResourceId)
override fun getTitle() = context.getString(R.string.module_installer_title)
@@ -32,24 +30,26 @@ class ModuleDownloaderPreference(context: Context, attrs: AttributeSet?) : Prefe
@SuppressLint("ApplySharedPref")
override fun onClick() {
setState(State.WORKING)
coroutineScope.launch {
GlobalScope.launch(Dispatchers.Main.immediate) {
try {
when (withContext(Dispatchers.IO) { Application.getModuleLoader().download() }) {
OsConstants.ENOENT -> setState(State.NOTFOUND)
OsConstants.EXIT_SUCCESS -> {
setState(State.SUCCESS)
Application.getSharedPreferences().edit().remove("disable_kernel_module").commit()
CoroutineScope(Dispatchers.Default).launch {
val restartIntent = Intent(context, SettingsActivity::class.java)
restartIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
restartIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
Application.get().startActivity(restartIntent)
exitProcess(0)
GlobalScope.launch(Dispatchers.Main.immediate) {
withContext(Dispatchers.IO) {
val restartIntent = Intent(context, SettingsActivity::class.java)
restartIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
restartIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
Application.get().startActivity(restartIntent)
exitProcess(0)
}
}
}
else -> setState(State.FAILURE)
}
} catch (e: Exception) {
} catch (e: Throwable) {
setState(State.FAILURE)
Toast.makeText(context, ErrorMessages[e], Toast.LENGTH_LONG).show()
}
@@ -10,8 +10,8 @@ import androidx.preference.Preference
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.util.ToolsInstaller
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -21,15 +21,13 @@ import kotlinx.coroutines.withContext
*/
class ToolsInstallerPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
private var state = State.INITIAL
private val coroutineScope = CoroutineScope(Dispatchers.Main)
override fun getSummary() = context.getString(state.messageResourceId)
override fun getTitle() = context.getString(R.string.tools_installer_title)
override fun onAttached() {
super.onAttached()
coroutineScope.launch {
GlobalScope.launch(Dispatchers.Main.immediate) {
try {
val state = withContext(Dispatchers.IO) { Application.getToolsInstaller().areInstalled() }
when {
@@ -39,7 +37,7 @@ class ToolsInstallerPreference(context: Context, attrs: AttributeSet?) : Prefere
state and (ToolsInstaller.SYSTEM or ToolsInstaller.NO) == ToolsInstaller.SYSTEM or ToolsInstaller.NO -> setState(State.INITIAL_SYSTEM)
else -> setState(State.INITIAL)
}
} catch (_: Exception) {
} catch (_: Throwable) {
setState(State.INITIAL)
}
}
@@ -47,7 +45,7 @@ class ToolsInstallerPreference(context: Context, attrs: AttributeSet?) : Prefere
override fun onClick() {
setState(State.WORKING)
coroutineScope.launch {
GlobalScope.launch(Dispatchers.Main.immediate) {
try {
val result = withContext(Dispatchers.IO) { Application.getToolsInstaller().install() }
when {
@@ -55,7 +53,7 @@ class ToolsInstallerPreference(context: Context, attrs: AttributeSet?) : Prefere
result and (ToolsInstaller.YES or ToolsInstaller.SYSTEM) == ToolsInstaller.YES or ToolsInstaller.SYSTEM -> setState(State.SUCCESS_SYSTEM)
else -> setState(State.FAILURE)
}
} catch (_: Exception) {
} catch (_: Throwable) {
setState(State.FAILURE)
}
}
@@ -16,8 +16,8 @@ import com.wireguard.android.R
import com.wireguard.android.backend.Backend
import com.wireguard.android.backend.GoBackend
import com.wireguard.android.backend.WgQuickBackend
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.Locale
@@ -47,16 +47,16 @@ class VersionPreference(context: Context, attrs: AttributeSet?) : Preference(con
}
init {
Application.getBackendAsync().thenAccept { backend ->
GlobalScope.launch(Dispatchers.Main.immediate) {
val backend = Application.getBackend()
versionSummary = getContext().getString(R.string.version_summary_checking, getBackendPrettyName(context, backend).toLowerCase(Locale.ENGLISH))
CoroutineScope(Dispatchers.Main).launch {
versionSummary = try {
getContext().getString(R.string.version_summary, getBackendPrettyName(context, backend), withContext(Dispatchers.IO) { backend.version })
} catch (_: Exception) {
getContext().getString(R.string.version_summary_unknown, getBackendPrettyName(context, backend).toLowerCase(Locale.ENGLISH))
}
notifyChanged()
notifyChanged()
versionSummary = try {
getContext().getString(R.string.version_summary, getBackendPrettyName(context, backend), withContext(Dispatchers.IO) { backend.version })
} catch (_: Throwable) {
getContext().getString(R.string.version_summary_unknown, getBackendPrettyName(context, backend).toLowerCase(Locale.ENGLISH))
}
notifyChanged()
}
}
}
@@ -13,13 +13,18 @@ import androidx.preference.Preference
import com.google.android.material.snackbar.Snackbar
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.model.ObservableTunnel
import com.wireguard.android.util.AdminKnobs
import com.wireguard.android.util.BiometricAuthenticator
import com.wireguard.android.util.DownloadsFileSaver
import com.wireguard.android.util.AdminKnobs
import com.wireguard.android.util.ErrorMessages
import com.wireguard.android.util.FragmentUtils
import java9.util.concurrent.CompletableFuture
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.nio.charset.StandardCharsets
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
@@ -29,52 +34,40 @@ import java.util.zip.ZipOutputStream
*/
class ZipExporterPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
private var exportedFilePath: String? = null
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()) {
exportZipComplete(null, IllegalArgumentException(
context.getString(R.string.no_tunnels_error)))
return
}
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()
GlobalScope.launch(Dispatchers.Main.immediate) {
val tunnels = Application.getTunnelManager().getTunnels()
try {
exportedFilePath = withContext(Dispatchers.IO) {
val configs = tunnels.map { async(SupervisorJob()) { it.getConfigAsync() } }.awaitAll()
if (configs.isEmpty()) {
throw IllegalArgumentException(context.getString(R.string.no_tunnels_error))
}
val outputFile = DownloadsFileSaver.save(context, "wireguard-export.zip", "application/zip", true)
try {
ZipOutputStream(outputFile.outputStream).use { zip ->
for (i in configs.indices) {
zip.putNextEntry(ZipEntry(tunnels[i].name + ".conf"))
zip.write(configs[i].toWgQuickString().toByteArray(StandardCharsets.UTF_8))
}
} catch (e: Exception) {
outputFile.delete()
throw e
zip.closeEntry()
}
outputFile.fileName
}.whenComplete(this::exportZipComplete)
} catch (e: Throwable) {
outputFile.delete()
throw e
}
outputFile.fileName
}
}
private fun exportZipComplete(filePath: String?, throwable: Throwable?) {
if (throwable != null) {
val error = ErrorMessages[throwable]
val message = context.getString(R.string.zip_export_error, error)
Log.e(TAG, message, throwable)
Snackbar.make(
FragmentUtils.getPrefActivity(this).findViewById(android.R.id.content),
message, Snackbar.LENGTH_LONG).show()
isEnabled = true
} else {
exportedFilePath = filePath
notifyChanged()
notifyChanged()
} catch (e: Throwable) {
val error = ErrorMessages[e]
val message = context.getString(R.string.zip_export_error, error)
Log.e(TAG, message, e)
Snackbar.make(
FragmentUtils.getPrefActivity(this@ZipExporterPreference).findViewById(android.R.id.content),
message, Snackbar.LENGTH_LONG).show()
isEnabled = true
}
}
}