diff --git a/core/src/main/java/com/omega_r/base/remote/CoroutineCallAdapterFactory.kt b/core/src/main/java/com/omega_r/base/remote/CoroutineCallAdapterFactory.kt index f99aec5..3f293c3 100644 --- a/core/src/main/java/com/omega_r/base/remote/CoroutineCallAdapterFactory.kt +++ b/core/src/main/java/com/omega_r/base/remote/CoroutineCallAdapterFactory.kt @@ -1,121 +1,64 @@ package com.omega_r.base.remote -import com.squareup.moshi.Types.getRawType -import kotlinx.coroutines.CompletableDeferred -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.Job -import retrofit2.Call -import retrofit2.CallAdapter -import retrofit2.Callback -import retrofit2.HttpException -import retrofit2.Response -import retrofit2.Retrofit -import java.lang.reflect.ParameterizedType +import com.omega_r.base.errors.ErrorHandler +import com.omega_r.libs.extensions.common.ifNull +import okhttp3.Request +import retrofit2.* import java.lang.reflect.Type -/** - * A [CallAdapter.Factory] for use with Kotlin coroutines. - * - * Adding this class to [Retrofit] allows you to return [Deferred] from - * service methods. - * - * interface MyService { - * @GET("user/me") - * Deferred<User> getUser() - * } - * - * There are two configurations supported for the [Deferred] type parameter: - * - * * Direct body (e.g., `Deferred`) returns the deserialized body for 2XX responses, throws - * [HttpException] errors for non-2XX responses, and throws [IOException][java.io.IOException] for - * network errors. - * * Response wrapped body (e.g., `Deferred>`) returns a [Response] object for all - * HTTP responses and throws [IOException][java.io.IOException] for network errors - */ -class CoroutineCallAdapterFactory (private val parent: Job? = null, - private val errorConverter: ((Throwable) -> Exception)? = null) : CallAdapter.Factory() { - - - override fun get(returnType: Type, annotations: Array, retrofit: Retrofit): CallAdapter<*, *>? { - if (Deferred::class.java != getRawType(returnType)) { - return null - } - if (returnType !is ParameterizedType) { - throw IllegalStateException( - "Deferred return type must be parameterized as Deferred or Deferred") - } - val responseType = getParameterUpperBound(0, returnType) - - val rawDeferredType = getRawType(responseType) - return if (rawDeferredType == Response::class.java) { - check(responseType is ParameterizedType) { "Response must be parameterized as Response or Response" } - ResponseCallAdapter(getParameterUpperBound(0, responseType), parent, errorConverter) - } else { - BodyCallAdapter(responseType, parent, errorConverter) - } +class CoroutineCallAdapterFactory(private val errorConverter: ((Throwable) -> Exception)? = ErrorHandler()) : CallAdapter.Factory() { + + override fun get(returnType: Type, annotations: Array, retrofit: Retrofit): CallAdapter<*, *>? { + val callAdapter = retrofit.nextCallAdapter(this, returnType, annotations) + return CallAdapterWrapper(callAdapter) } - private class BodyCallAdapter(private val responseType: Type, - private val parent: Job? = null, - private val errorConverter: ((Throwable) -> Exception)? = null) : CallAdapter> { + inner class CallAdapterWrapper(private val adapter: CallAdapter) : CallAdapter { - override fun responseType() = responseType + override fun adapt(call: Call): T = adapter.adapt(CallWrapper(call)) - override fun adapt(call: Call): Deferred { - val deferred = CompletableDeferred(parent) + override fun responseType(): Type = adapter.responseType() - deferred.invokeOnCompletion { - if (deferred.isCancelled) { - call.cancel() - } - } + } + + inner class CallWrapper(private val delegate: Call) : Call { + + override fun enqueue(callback: Callback) { + delegate.enqueue(object : Callback { - call.enqueue(object : Callback { - override fun onFailure(call: Call, t: Throwable) { - deferred.completeExceptionally(errorConverter?.invoke(t) ?: t) + override fun onFailure(call: Call, t: Throwable) { + callback.onFailure(call, errorConverter?.invoke(t) ?: t) } - override fun onResponse(call: Call, response: Response) { + override fun onResponse(call: Call, response: Response) { if (response.isSuccessful) { - deferred.complete(response.body()) + callback.onResponse(call, response) } else { - val httpException = HttpException(response) - deferred.completeExceptionally(errorConverter?.invoke(httpException) ?: httpException) + errorConverter?.invoke(HttpException(response))?.let { + callback.onFailure(call, it) + }.ifNull { + callback.onResponse(call, response) + } } } }) - return deferred } - } - private class ResponseCallAdapter(private val responseType: Type, - private val parent: Job? = null, - private val errorConverter: ((Throwable) -> Exception)? = null - ) : CallAdapter>> { + override fun isExecuted(): Boolean = delegate.isExecuted - override fun responseType() = responseType + override fun clone(): Call = CallWrapper(delegate.clone()) - override fun adapt(call: Call): Deferred> { - val deferred = CompletableDeferred>(parent) + override fun isCanceled(): Boolean = delegate.isCanceled - deferred.invokeOnCompletion { - if (deferred.isCancelled) { - call.cancel() - } - } + override fun cancel() { + delegate.cancel() + } - call.enqueue(object : Callback { - override fun onFailure(call: Call, t: Throwable) { - deferred.completeExceptionally(errorConverter?.invoke(t) ?: t) - } + override fun execute(): Response = delegate.execute() - override fun onResponse(call: Call, response: Response) { - deferred.complete(response) - } - }) + override fun request(): Request = delegate.request() - return deferred - } } -} + +} \ No newline at end of file