Created
January 17, 2018 14:28
-
-
Save morj/223e53326a6df994a92c260a474fa0a1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open class SuspendAwareThrowable(message: String?) : Throwable(message) { | |
companion object : KLogging() | |
private val _cause = AtomicReference<Throwable>(null) | |
override fun fillInStackTrace(): Throwable { | |
return if (logger.isDebugEnabled) { | |
super.fillInStackTrace() | |
} else { | |
this | |
} | |
} | |
override var cause: Throwable? | |
get() = _cause.get() | |
set(value) { | |
if (!_cause.compareAndSet(null, value)) { | |
throw IllegalStateException("Cannot modify cause because it's already set (see cause of this one)", _cause.get()) | |
} | |
} | |
} | |
class CallNotExecutedException(message: String?) : SuspendAwareThrowable(message) | |
internal class CallFailedException(message: String?) : Throwable(message) | |
// retrofit2 async Call to suspend fun interoperability | |
suspend fun <T> Call<T>.invokeAsync(): T { | |
val channel = Channel<T>(capacity = UNLIMITED) | |
val callSite = CallNotExecutedException(request().url()?.toString()) // remember invocation point | |
enqueue(object : Callback<T> { | |
override fun onResponse(call: Call<T>, response: retrofit2.Response<T>) { | |
val result = response.body() | |
if (result != null && call.isExecuted && response.isSuccessful) { | |
channel.offer(result) | |
} else { | |
channel.cancel(CallFailedException(response.errorBody()?.string())) | |
} | |
} | |
override fun onFailure(call: Call<T>, t: Throwable) { | |
channel.cancel(t) | |
} | |
}) | |
return try { | |
channel.receive() | |
} catch (t: Throwable) { | |
callSite.cause = t | |
throw callSite | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment