Fix coroutines cancellation

This commit is contained in:
Koitharu
2022-09-21 18:35:38 +03:00
parent 73478d6a81
commit 1e75edf262
33 changed files with 217 additions and 130 deletions

View File

@@ -1,50 +0,0 @@
package org.koitharu.kotatsu.utils
import androidx.annotation.MainThread
import java.util.concurrent.ConcurrentLinkedQueue
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Runnable
class PausingDispatcher(
private val dispatcher: CoroutineDispatcher,
) : CoroutineDispatcher() {
@Volatile
private var isPaused = false
private val queue = ConcurrentLinkedQueue<Task>()
override fun isDispatchNeeded(context: CoroutineContext): Boolean {
return isPaused || super.isDispatchNeeded(context)
}
override fun dispatch(context: CoroutineContext, block: Runnable) {
if (isPaused) {
queue.add(Task(context, block))
} else {
dispatcher.dispatch(context, block)
}
}
@MainThread
fun pause() {
isPaused = true
}
@MainThread
fun resume() {
if (!isPaused) {
return
}
isPaused = false
while (true) {
val task = queue.poll() ?: break
dispatcher.dispatch(task.context, task.block)
}
}
private class Task(
val context: CoroutineContext,
val block: Runnable,
)
}

View File

@@ -46,7 +46,7 @@ val Context.connectivityManager: ConnectivityManager
fun String.toUriOrNull() = if (isEmpty()) null else Uri.parse(this)
suspend fun CoroutineWorker.trySetForeground(): Boolean = runCatching {
suspend fun CoroutineWorker.trySetForeground(): Boolean = runCatchingCancellable {
val info = getForegroundInfo()
setForeground(info)
}.isSuccess
@@ -95,6 +95,7 @@ fun SyncResult.onError(error: Throwable) {
is OperationApplicationException,
is SQLException,
-> databaseError = true
is JSONException -> stats.numParseExceptions++
else -> if (BuildConfig.DEBUG) throw error
}

View File

@@ -3,16 +3,22 @@ package org.koitharu.kotatsu.utils.ext
import android.content.ActivityNotFoundException
import android.content.res.Resources
import androidx.collection.arraySetOf
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import kotlinx.coroutines.CancellationException
import okio.FileNotFoundException
import org.acra.ktx.sendWithAcra
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.*
import org.koitharu.kotatsu.core.exceptions.CaughtException
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException
import org.koitharu.kotatsu.core.exceptions.SyncApiException
import org.koitharu.kotatsu.core.exceptions.UnsupportedFileException
import org.koitharu.kotatsu.core.exceptions.WrongPasswordException
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
import org.koitharu.kotatsu.parsers.exception.ContentUnavailableException
import org.koitharu.kotatsu.parsers.exception.NotFoundException
import org.koitharu.kotatsu.parsers.exception.ParseException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
fun Throwable.getDisplayMessage(resources: Resources): String = when (this) {
is AuthRequiredException -> resources.getString(R.string.auth_required)
@@ -20,16 +26,19 @@ fun Throwable.getDisplayMessage(resources: Resources): String = when (this) {
is ActivityNotFoundException,
is UnsupportedOperationException,
-> resources.getString(R.string.operation_not_supported)
is UnsupportedFileException -> resources.getString(R.string.text_file_not_supported)
is FileNotFoundException -> resources.getString(R.string.file_not_found)
is EmptyHistoryException -> resources.getString(R.string.history_is_empty)
is SyncApiException,
is ContentUnavailableException,
-> message
is ParseException -> shortMessage
is UnknownHostException,
is SocketTimeoutException,
-> resources.getString(R.string.network_error)
is WrongPasswordException -> resources.getString(R.string.wrong_password)
is NotFoundException -> resources.getString(R.string.not_found_404)
else -> localizedMessage
@@ -52,3 +61,15 @@ private val reportableExceptions = arraySetOf<Class<*>>(
ConcurrentModificationException::class.java,
UnsupportedOperationException::class.java,
)
inline fun <R> runCatchingCancellable(block: () -> R): Result<R> {
return try {
Result.success(block())
} catch (e: InterruptedException) {
throw e
} catch (e: CancellationException) {
throw e
} catch (e: Throwable) {
Result.failure(e)
}
}