Generi c GRP c запросов в kotlin - PullRequest
       11

Generi c GRP c запросов в kotlin

1 голос
/ 15 апреля 2020
class API {

    val nonBlockingStub: HealthcareAPIGrpc.HealthcareAPIStub //Generated Java GRPC Stub

    suspend fun exampleRequest(params: Params) : ReturnedResult = suspendCancellableCoroutine { routine ->
        val obs = object : StreamObserver<ReturnedResult> {
            override fun onNext(value: ReturnedResult?) {
                routine.resume(value!!)
            }

            override fun onError(t: Throwable?) {
                routine.resumeWithException(t!!)
            }

            override fun onCompleted() {
            }
        }
        nonBlockingStub.exampleRequest(params, obs)
    }
}

Итак, я работаю над приложением Kotlin android, в котором есть клиент grp c, сгенерированный в java. Недавно мне пришлось перенести все запросы API на использование kotlin сопрограмм. Для каждого запроса я должен скопировать и вставить эту функцию exampleRequest.

Мне интересно, можно ли создать обобщенную функцию c, которая делает это, принимает некоторые параметры и вызывает базовую функцию-заглушку

1 Ответ

2 голосов
/ 16 апреля 2020

В идеале должен быть генератор заглушки, который генерирует соответствующие вызовы как suspend / Flow методы, но вы все равно можете абстрагировать большую часть преобразования с помощью специальной вспомогательной функции:

fun <T> grpcFlow(
    @BuilderInference block: suspend (StreamObserver<T>) -> Unit
): Flow<T> = callbackFlow {
    // Use ClientCallStreamObserver to support cancellation
    val observer = object : ClientCallStreamObserver<T>() {
        override fun onNext(value: T) {
            sendBlocking(value)
        }

        override fun onError(t: Throwable) {
            cancel(CancellationException("GRPC Error", t))
        }

        override fun onCompleted() = channel.close()
    }

    block(observer)

    awaitClose { 
        observer.cancel("flow cancellation", null)
    }
}

Тогда ваш API просто становится:

class API {
    val nonBlockingStub: HealthcareAPIGrpc.HealthcareAPIStub

    suspend fun exampleRequest(params: Params) = grpcFlow {
        // @BuilderInference should ensure the correct type is used
        nonBlockingStub.exampleRequest(params, it)
    }.single() // Since we only expect a single response value.

    // And for returns (stream ReturnedResult)
    suspend fun exampleStreamingRequest(params: Params) = gcpcFlow {
        nonBlockingStub.exampleStreamingRequest(params, it)
    } // Flow<ReturnedResult>

}
...