简体   繁体   English

kotlin 中的通用 grpc 请求

[英]Generic grpc requests in kotlin

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)
    }
}

So I'm working on an Kotlin android application, which has a grpc client generated in java.所以我正在开发一个 Kotlin android 应用程序,它有一个在 java 中生成的 grpc 客户端。 Recently I had to move all the API requests to use kotlin coroutines.最近我不得不移动所有 API 请求以使用 kotlin 协程。 For every request I have to copy-paste this exampleRequest function.对于每个请求,我都必须复制粘贴这个 exampleRequest function。

I am curious if it's possible to make a generic function which does this, takes some params and calls the underlying stub function我很好奇是否有可能制作一个通用的 function 这样做,需要一些参数并调用底层存根 function

Ideally there should be a stub generator that generates the appropriate calls as suspend / Flow methods, but you can still abstract much of the conversion with a dedicated helper function:理想情况下,应该有一个存根生成器生成适当的调用作为suspend / Flow方法,但您仍然可以使用专用帮助器 function 抽象大部分转换:

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)
    }
}

Then your API simply becomes:然后你的 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>

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM