Created
February 25, 2019 02:10
-
-
Save digitalbuddha/61e06b1b97ccf284ce796369f0632da2 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
package com.jakewharton.retrofit2.adapter.kotlin.coroutines | |
import com.nytimes.android.external.store3.base.DiskRead | |
import com.nytimes.android.external.store3.base.DiskWrite | |
import com.nytimes.android.external.store3.base.Fetcher | |
import com.nytimes.android.external.store3.base.impl.RealStoreBuilder | |
import com.nytimes.android.external.store3.base.impl.Store | |
import com.nytimes.android.external.store3.base.impl.StoreBuilder | |
import com.nytimes.android.sample.data.remote.Persister | |
import com.nytimes.android.sample.data.remote.RefershOnStale | |
import kotlinx.coroutines.suspendCancellableCoroutine | |
import retrofit2.* | |
import java.lang.reflect.ParameterizedType | |
import java.lang.reflect.Type | |
class StoreCallAdapterFactory private constructor() : CallAdapter.Factory() { | |
val stores = mutableMapOf<Type, StoreCallAdapter<Any>>() | |
companion object { | |
@JvmStatic | |
@JvmName("create") | |
operator fun invoke() = StoreCallAdapterFactory() | |
} | |
override fun get( | |
returnType: Type, | |
annotations: Array<out Annotation>, | |
retrofit: Retrofit | |
): CallAdapter<*, *>? { | |
if (Store::class.java != getRawType(returnType)) { | |
return null | |
} | |
if (returnType !is ParameterizedType) { | |
throw IllegalStateException( | |
"Store return type must be parameterized as Store<Foo> or Store<out Foo>") | |
} | |
val responseType = getParameterUpperBound(0, returnType) | |
return stores.getOrPut(responseType) { StoreCallAdapter(responseType, annotations) } | |
} | |
class StoreCallAdapter<T>( | |
private val responseType: Type, | |
private val annotations: Array<out Annotation> | |
) : CallAdapter<T, Store<T, Call<T>>> { | |
var store: Store<T, Call<T>>? = null | |
@Synchronized | |
override fun adapt(call: Call<T>): Store<T, Call<T>> { | |
if (store == null) { | |
val builder = StoreBuilder.key<Call<T>, T>() | |
builder.fetcher(object : Fetcher<T, Call<T>> { | |
override suspend fun fetch(myCall: Call<T>) = myCall.await() | |
}) | |
//add Configuration for parsing/chaching | |
annotations | |
.map { it.javaClass } | |
.forEach { | |
when (it) { | |
Persister::class.java -> addPersister(builder, call) | |
RefershOnStale::class.java -> builder.refreshOnStale() | |
} | |
} | |
store = builder.open() | |
} | |
return store!! | |
} | |
override fun responseType() = responseType | |
private fun addPersister(builder: RealStoreBuilder<T, T, Call<T>>, call: Call<T>) = | |
builder.persister(object : DiskRead<T, Call<T>> { | |
override suspend fun read(key: Call<T>): T? { | |
val key = call.request() | |
return null | |
} | |
}, object : DiskWrite<T, Call<T>> { | |
override suspend fun write(key: Call<T>, raw: T): Boolean = true | |
}) | |
} | |
} | |
suspend fun <T : Any> Call<T>.await(): T { | |
return suspendCancellableCoroutine { continuation -> | |
continuation.invokeOnCancellation { | |
cancel() | |
} | |
enqueue(object : Callback<T> { | |
override fun onResponse(call: Call<T>, response: Response<T>) { | |
if (response.isSuccessful) { | |
val body = response.body() | |
if (body == null) { | |
val invocation = call.request().tag(Invocation::class.java)!! | |
val method = invocation.method() | |
val e = KotlinNullPointerException("Response from " + | |
method.declaringClass.name + | |
'.' + | |
method.name + | |
" was null but response body type was declared as non-null") | |
continuation.resumeWithException(e) | |
} else { | |
continuation.resume(body) | |
} | |
} else { | |
continuation.resumeWithException(HttpException(response)) | |
} | |
} | |
override fun onFailure(call: Call<T>, t: Throwable) { | |
continuation.resumeWithException(t) | |
} | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment