diff options
| author | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2020-12-11 15:03:29 +0000 |
|---|---|---|
| committer | Janito Vaqueiro Ferreira Filho <janito@mullvad.net> | 2020-12-14 13:22:56 +0000 |
| commit | 7ee3dcc5b46faef4bc0c0aee0231f1a66a12b148 (patch) | |
| tree | b813dc144587deff97c57c838bed8e6db866ce15 /android/src/main | |
| parent | 9810fc6f52bd678f74afbf494c1dda851aee3843 (diff) | |
| download | mullvadvpn-7ee3dcc5b46faef4bc0c0aee0231f1a66a12b148.tar.xz mullvadvpn-7ee3dcc5b46faef4bc0c0aee0231f1a66a12b148.zip | |
Refactor `MullvadProblemReport` to be an actor
Diffstat (limited to 'android/src/main')
| -rw-r--r-- | android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/MullvadProblemReport.kt | 142 |
1 files changed, 78 insertions, 64 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/MullvadProblemReport.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/MullvadProblemReport.kt index 12dd4cd43b..ae2d1b2df2 100644 --- a/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/MullvadProblemReport.kt +++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/dataproxy/MullvadProblemReport.kt @@ -5,114 +5,128 @@ import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.Deferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.Job import kotlinx.coroutines.async -import kotlinx.coroutines.launch +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.ClosedReceiveChannelException +import kotlinx.coroutines.channels.actor +import kotlinx.coroutines.channels.sendBlocking const val PROBLEM_REPORT_FILE = "problem_report.txt" class MullvadProblemReport { + private sealed class Command { + class Collect() : Command() + class Load(val logs: CompletableDeferred<String>) : Command() + class Send(val result: CompletableDeferred<Boolean>) : Command() + class Delete() : Command() + } + val logDirectory = CompletableDeferred<File>() val resourcesDirectory = CompletableDeferred<File>() + private val commandChannel = spawnActor() + private val problemReportPath = GlobalScope.async(Dispatchers.Default) { File(logDirectory.await(), PROBLEM_REPORT_FILE) } - private var collectJob: Deferred<Boolean>? = null - private var sendJob: Deferred<Boolean>? = null - private var deleteJob: Job? = null + private var isCollected = false var confirmNoEmail: CompletableDeferred<Boolean>? = null var userEmail = "" var userMessage = "" - val isActive: Boolean - get() { - synchronized(this) { - val collectJob = this.collectJob - val sendJob = this.sendJob - - return (collectJob != null && collectJob.isActive) || - (sendJob != null && sendJob.isActive) - } - } - init { System.loadLibrary("mullvad_jni") } fun collect() { - synchronized(this) { - if (!isActive) { - collectJob = GlobalScope.async(Dispatchers.Default) { - val logDirectoryPath = logDirectory.await().absolutePath - val reportPath = problemReportPath.await().absolutePath - - deleteReportFile().join() - collectReport(logDirectoryPath, reportPath) - } - } - } + commandChannel.sendBlocking(Command.Collect()) } suspend fun load(): String { - if (collectJob == null) { - collect() - } + val logs = CompletableDeferred<String>() - if (collectJob?.await() ?: false) { - return problemReportPath.await().readText() - } else { - return "Failed to collect logs for problem report" - } + commandChannel.send(Command.Load(logs)) + + return logs.await() } fun send(): Deferred<Boolean> { - synchronized(this) { - var currentJob = sendJob + val result = CompletableDeferred<Boolean>() - if (currentJob == null || currentJob.isCompleted) { - currentJob = GlobalScope.async(Dispatchers.Default) { - val result = (collectJob?.await() ?: false) && - sendProblemReport( - userEmail, - userMessage, - problemReportPath.await().absolutePath, - resourcesDirectory.await().absolutePath - ) + commandChannel.sendBlocking(Command.Send(result)) - if (result) { - deleteReportFile() - } + return result + } - result - } + fun deleteReportFile() { + commandChannel.sendBlocking(Command.Delete()) + } - sendJob = currentJob - } + private fun spawnActor() = GlobalScope.actor<Command>(Dispatchers.Default, Channel.UNLIMITED) { + try { + while (true) { + val command = channel.receive() - return currentJob + when (command) { + is Command.Collect -> doCollect() + is Command.Load -> command.logs.complete(doLoad()) + is Command.Send -> command.result.complete(doSend()) + is Command.Delete -> doDelete() + } + } + } catch (exception: ClosedReceiveChannelException) { } } - fun deleteReportFile(): Job { - synchronized(this) { - val oldDeleteJob = deleteJob + private suspend fun doCollect() { + val logDirectoryPath = logDirectory.await().absolutePath + val reportPath = problemReportPath.await().absolutePath - val job = GlobalScope.launch(Dispatchers.Default) { - oldDeleteJob?.join() - problemReportPath.await().delete() - collectJob = null - } + doDelete() + + isCollected = collectReport(logDirectoryPath, reportPath) + } - deleteJob = job + private suspend fun doLoad(): String { + if (!isCollected) { + doCollect() + } - return job + if (isCollected) { + return problemReportPath.await().readText() + } else { + return "Failed to collect logs for problem report" } } + private suspend fun doSend(): Boolean { + if (!isCollected) { + doCollect() + } + + val result = isCollected && + sendProblemReport( + userEmail, + userMessage, + problemReportPath.await().absolutePath, + resourcesDirectory.await().absolutePath + ) + + if (result) { + doDelete() + } + + return result + } + + private suspend fun doDelete() { + problemReportPath.await().delete() + isCollected = false + } + private external fun collectReport(logDirectory: String, reportPath: String): Boolean private external fun sendProblemReport( userEmail: String, |
