Skip to content

Instantly share code, notes, and snippets.

@morj
Created January 17, 2018 14:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save morj/223e53326a6df994a92c260a474fa0a1 to your computer and use it in GitHub Desktop.
Save morj/223e53326a6df994a92c260a474fa0a1 to your computer and use it in GitHub Desktop.
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