add defaultSafelyExceptionHandler and SafelyExceptionHandler

This commit is contained in:
InsanusMokrassar 2020-12-22 15:16:06 +06:00
parent a15cbdfb1a
commit 069e51f2ff
3 changed files with 35 additions and 7 deletions

View File

@ -3,9 +3,13 @@
## 0.4.14 ## 0.4.14
* `Versions`: * `Versions`:
* `Kotlin`: `1.4.20` -> `1.4.21` * `Kotlin`: `1.4.20` -> `1.4.21`
* `Ktor`: `1.4.3` -> `1.5.0` * `Ktor`: `1.4.3` -> `1.5.0`
* `Klock`: `2.0.1` -> `2.0.2` * `Klock`: `2.0.1` -> `2.0.2`
* `Coroutines`:
* Add global variable `defaultSafelyExceptionHandler`
* Add `SafelyExceptionHandlerKey` and `SafelyExceptionHandler` classes to be able to overwrite
`defaultSafelyExceptionHandler` using context of coroutine
## 0.4.13 ## 0.4.13

View File

@ -2,23 +2,47 @@ package dev.inmo.micro_utils.coroutines
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.supervisorScope
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
typealias ExceptionHandler<T> = suspend (Throwable) -> T typealias ExceptionHandler<T> = suspend (Throwable) -> T
/**
* This instance will be used in all calls of [safely] where exception handler has not been passed
*/
var defaultSafelyExceptionHandler: ExceptionHandler<Nothing> = { throw it }
class SafelyExceptionHandlerKey<T> : CoroutineContext.Key<SafelyExceptionHandler<T>>
inline fun <T> safelyExceptionHandlerKey() = SafelyExceptionHandlerKey<T>()
class SafelyExceptionHandler<T>(
val handler: ExceptionHandler<T>
) : CoroutineContext.Element {
override val key: CoroutineContext.Key<*> = safelyExceptionHandlerKey<T>()
}
/** /**
* It will run [block] inside of [supervisorScope] to avoid problems with catching of exceptions * It will run [block] inside of [supervisorScope] to avoid problems with catching of exceptions
* *
* @param [onException] Will be called when happen exception inside of [block]. By default will throw exception - this * @param [onException] Will be called when happen exception inside of [block]. By default will throw exception - this
* exception will be available for catching * exception will be available for catching
*
* @see defaultSafelyExceptionHandler
* @see safelyWithoutExceptions
*/ */
suspend inline fun <T> safely( suspend inline fun <T> safely(
noinline onException: ExceptionHandler<T> = { throw it }, noinline onException: ExceptionHandler<T> = defaultSafelyExceptionHandler,
noinline block: suspend CoroutineScope.() -> T noinline block: suspend CoroutineScope.() -> T
): T { ): T {
return try { return try {
supervisorScope(block) supervisorScope(block)
} catch (e: Throwable) { } catch (e: Throwable) {
onException(e) val handler = if (onException == defaultSafelyExceptionHandler) {
coroutineContext[safelyExceptionHandlerKey<T>()] ?.handler ?: onException
} else {
onException
}
handler(e)
} }
} }

View File

@ -25,7 +25,7 @@ inline fun <T> HttpClient.createStandardWebsocketFlow(
val producerScope = this@channelFlow val producerScope = this@channelFlow
do { do {
val reconnect = try { val reconnect = try {
safely ({ throw it }) { safely {
ws(correctedUrl) { ws(correctedUrl) {
for (received in incoming) { for (received in incoming) {
when (received) { when (received) {