Fix coroutines cancellation
This commit is contained in:
@@ -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,
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user