Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin 如何实现消息中重复的gRPC/Proto端点(即请求和响应中的嵌套类型)_Kotlin_Protocol Buffers_Grpc_Micronaut_Grpc Java - Fatal编程技术网

Kotlin 如何实现消息中重复的gRPC/Proto端点(即请求和响应中的嵌套类型)

Kotlin 如何实现消息中重复的gRPC/Proto端点(即请求和响应中的嵌套类型),kotlin,protocol-buffers,grpc,micronaut,grpc-java,Kotlin,Protocol Buffers,Grpc,Micronaut,Grpc Java,目标:我想编写一个微服务代码,公开一个端点,该端点接收并响应一条重复的消息。我试着应用我从中学到的知识,并编写了这个原型: syntax = "proto3"; option java_multiple_files = true; option java_package = "com.mybank.endpoint"; option java_outer_classname = "TransactionsProto"; option

目标:我想编写一个微服务代码,公开一个端点,该端点接收并响应一条重复的消息。我试着应用我从中学到的知识,并编写了这个原型:

syntax = "proto3";

option java_multiple_files = true;
option java_package = "com.mybank.endpoint";
option java_outer_classname = "TransactionsProto";
option objc_class_prefix = "HLW";

package com.mybank.endpoint;

import "google/protobuf/wrappers.proto";

service TransactionsService {
  rpc PostTransactions(TransactionsRequest) returns (TransactionsReply);
}

message TransactionsRequest {
  string transactionDesc = 1;
  repeated Transaction transactions = 2;
}
message Transaction {
  string id = 1;
  string name = 2;
  string description = 3;
}

message TransactionsReply {
  string message = 1;
}
我可以进行梯度构建,并自动生成这个TransactionsServiceGrpcKt

package com.mybank.endpoint

import com.mybank.endpoint.TransactionsServiceGrpc.getServiceDescriptor
import io.grpc.CallOptions
import io.grpc.CallOptions.DEFAULT
import io.grpc.Channel
import io.grpc.Metadata
import io.grpc.MethodDescriptor
import io.grpc.ServerServiceDefinition
import io.grpc.ServerServiceDefinition.builder
import io.grpc.ServiceDescriptor
import io.grpc.Status.UNIMPLEMENTED
import io.grpc.StatusException
import io.grpc.kotlin.AbstractCoroutineServerImpl
import io.grpc.kotlin.AbstractCoroutineStub
import io.grpc.kotlin.ClientCalls.unaryRpc
import io.grpc.kotlin.ServerCalls.unaryServerMethodDefinition
import io.grpc.kotlin.StubFor
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.jvm.JvmOverloads
import kotlin.jvm.JvmStatic

/**
 * Holder for Kotlin coroutine-based client and server APIs for
 * com.mybank.endpoint.TransactionsService.
 */
object TransactionsServiceGrpcKt {
  @JvmStatic
  val serviceDescriptor: ServiceDescriptor
    get() = TransactionsServiceGrpc.getServiceDescriptor()

  val postTransactionsMethod: MethodDescriptor<TransactionsRequest, TransactionsReply>
    @JvmStatic
    get() = TransactionsServiceGrpc.getPostTransactionsMethod()

  /**
   * A stub for issuing RPCs to a(n) com.mybank.endpoint.TransactionsService service as suspending
   * coroutines.
   */
  @StubFor(TransactionsServiceGrpc::class)
  class TransactionsServiceCoroutineStub @JvmOverloads constructor(
    channel: Channel,
    callOptions: CallOptions = DEFAULT
  ) : AbstractCoroutineStub<TransactionsServiceCoroutineStub>(channel, callOptions) {
    override fun build(channel: Channel, callOptions: CallOptions): TransactionsServiceCoroutineStub
        = TransactionsServiceCoroutineStub(channel, callOptions)

    /**
     * Executes this RPC and returns the response message, suspending until the RPC completes
     * with [`Status.OK`][io.grpc.Status].  If the RPC completes with another status, a
     * corresponding
     * [StatusException] is thrown.  If this coroutine is cancelled, the RPC is also cancelled
     * with the corresponding exception as a cause.
     *
     * @param request The request message to send to the server.
     *
     * @return The single response from the server.
     */
    suspend fun postTransactions(request: TransactionsRequest): TransactionsReply = unaryRpc(
      channel,
      TransactionsServiceGrpc.getPostTransactionsMethod(),
      request,
      callOptions,
      Metadata()
    )}

  /**
   * Skeletal implementation of the com.mybank.endpoint.TransactionsService service based on Kotlin
   * coroutines.
   */
  abstract class TransactionsServiceCoroutineImplBase(
    coroutineContext: CoroutineContext = EmptyCoroutineContext
  ) : AbstractCoroutineServerImpl(coroutineContext) {
    /**
     * Returns the response to an RPC for com.mybank.endpoint.TransactionsService.PostTransactions.
     *
     * If this method fails with a [StatusException], the RPC will fail with the corresponding
     * [io.grpc.Status].  If this method fails with a [java.util.concurrent.CancellationException],
     * the RPC will fail
     * with status `Status.CANCELLED`.  If this method fails for any other reason, the RPC will
     * fail with `Status.UNKNOWN` with the exception as a cause.
     *
     * @param request The request from the client.
     */
    open suspend fun postTransactions(request: TransactionsRequest): TransactionsReply = throw
        StatusException(UNIMPLEMENTED.withDescription("Method com.mybank.endpoint.TransactionsService.PostTransactions is unimplemented"))

    final override fun bindService(): ServerServiceDefinition = builder(getServiceDescriptor())
      .addMethod(unaryServerMethodDefinition(
      context = this.context,
      descriptor = TransactionsServiceGrpc.getPostTransactionsMethod(),
      implementation = ::postTransactions
    )).build()
  }
}
我已经成功地创建了我的第一个grpc端点,它具有基于字符串的非常基本的请求/回复,现在我想通过创建一个消息列表继续前进。作为类比,假设我想要一个DTO/Pojo,其中包含一个实体列表

老实说,我完全被卡住了。所以,我的主要问题是:如何实现具有重复消息的proto服务

一个有用的注释是,为什么我在自动生成的存根中看到一个用“…,responseObserver:StreamObserver?”实现的方法,而不是我在proto中明确指定的简单的“TransactionsReply”?StreamObserver和重复消息之间有什么关系

这是整个项目

您将发现两个原型:一个成功的实现,具有简单的请求/应答,另一个失败,如上所述

***根据路易斯的第一个答案进行编辑

我很困惑。 用一个简单的proto作为

...
service Account {
  rpc SendDebit (DebitRequest) returns (DebitReply) {}
}

message DebitRequest {
  string name = 1;
}

message DebitReply {
  string message = 1;
}
我可以用它来实现

override suspend fun sendDebit(request: DebitRequest): DebitReply {
    return DebitReply.newBuilder().setMessage("teste").build()
}
尽管如此

...
service TransactionsService {
  rpc PostTransactions(TransactionsRequest) returns (TransactionsReply);
}

message TransactionsRequest {
  string transactionDesc = 1;
  repeated Transaction transactions = 2;
}
message Transaction {
  string id = 1;
  string name = 2;
  string description = 3;
}

message TransactionsReply {
  string message = 1;
}
我无法使用相同类型的响应覆盖(请注意,响应完全相同)

这两种实现都不是由IntelliJ提出的

override fun postTransactions(request: TransactionsRequest?, responseObserver: StreamObserver<TransactionsReply>?) {
        super.postTransactions(request, responseObserver)
        return TransactionsReply.newBuilder().setMessage("testReply").build()
    }
你在找什么

class TransactionsEndpoint : TransactionsServiceGrpcKt.TransactionsServiceCoroutineImplBase(){
   override suspend fun postTransactions(request: TransactionsRequest) : TransactionsReply {
      ...
   }
}
…使用
suspend
修饰符,请求时不使用
,使用
Coroutine
扩展
TransactionServiceCoroutineImplBase

请注意,这与重复的消息无关。您的RPC有一个单一的输入协议,只发送一次——这很可能是您想要的,除非您想要一个请求流,在这种情况下,您的协议文件应该是这样的

service TransactionsService {
  rpc PostTransactions(stream TransactionsRequest) returns (TransactionsReply);
}

…在这种情况下,Kotlin生成的代码看起来会有所不同。

Louis,谢谢。很容易看出你知道我做错了什么,但我还不能纠正它。我对返回流不感兴趣(这次不是)。我只想编写返回嵌套对象的第一个enpoint代码,就像我们在Rest中使用dto时通常做的那样。我删除了supsend,因为我知道这不是我的情况。我刚刚了解到“…挂起的函数只能由另一个挂起的函数或在一个协同程序中调用…”。我尝试了上面的方法(见我编辑的答案),但没有成功。我不明白为什么用一个非常简单的原型,包含单个字符串的请求和应答,我成功地用“override suspend fun sendDebit(request:DebitRequest):DebitReply{return DebitReply.newBuilder().setMessage(“teste”).build()实现了它但是,仅仅因为我更改了请求,但保持了回复的一致性,我就不能同样地实现响应。当然,它更改了请求,但我希望响应是相同的。gRPC框架正在调用您的方法。将
suspend
保留在那里,但您不必以任何不同的方式实现它,也不必执行任何有助于花费。但是你能用
postTransactions
发布你用
suspend
版本尝试过的确切代码吗?你确定你用
Coroutine
扩展了正确的
ImplBase
类吗?非常感谢。这就是问题所在:我在扩展“TransactionServicegrpc.TransactionServiceImplbase”正确的应该是“TransactionServiceGrpCkt.TransactionServiceCoroutineImplBase”。今天正好是我学习Micronaut+GRPC+Proto+Kotlin的一个月,我有很多东西要学。
override fun postTransactions(request: TransactionsRequest?, responseObserver: StreamObserver<TransactionsReply>?) :TransactionsReply {
    super.postTransactions(request, responseObserver)
    return TransactionsReply.newBuilder().setMessage("testReply").build()
}
override suspend fun postTransactions(request: TransactionsRequest): TransactionsReply {
    return TransactionsReply.newBuilder().setMessage("testReply").build()
}
class TransactionsEndpoint : TransactionsServiceGrpcKt.TransactionsServiceCoroutineImplBase(){
   override suspend fun postTransactions(request: TransactionsRequest) : TransactionsReply {
      ...
   }
}
service TransactionsService {
  rpc PostTransactions(stream TransactionsRequest) returns (TransactionsReply);
}