Go中Any类型消息的自定义protobuf选项 [英] Custom protobuf options of message of type Any in Go

查看:277
本文介绍了Go中Any类型消息的自定义protobuf选项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个定义如下的GRPC服务:

I have a GRPC service defined like:

message SendEventRequest {
  string producer = 1;
  google.protobuf.Any event = 2;
}

message SendEventResponse {
  string event_name = 1;
  string status = 2;
}

service EventService {
  rpc Send(SendEventRequest) returns (SendEventResponse);
}

我还定义了一个自定义消息选项:

I also have defined a custom message option:

extend google.protobuf.MessageOptions {
  // event_name is the unique name of the event sent by the clients
  string event_name = 50000;
}

我要实现的是让客户端创建自定义的原始消息,该消息将 event_name 选项设置为"constant".例如:

What I want to achieve is have clients create custom proto messages that set the event_name option to a "constant". For instance:

message SomeCustomEvent {
  option (mypackage.event_name) = "some_custom_event";

  string data = 1;
  ...
}

这样,服务可以跟踪正在发送的事件.当我做这样的事情时,我能够从特定的 proto.Message :

That way the service can keep track of what events are being sent. When I do something like this I'm able to get the value of the option from a specific proto.Message:

_, md := descriptor.MessageDescriptorProto(SomeCustomEvent)
mOpts := md.GetOptions()
eventName := proto.GetExtension(mOpts, mypackage.E_EventName)

但是,当消息的类型为 github.com/golang/protobuf/ptypes/any.Any 时,选项为nil.如何从消息中检索 event_name ?我遇到过 protoregistry.MessageTypeResolver ,它看起来可能会有所帮助,但是我需要找出一种方法来在客户端集成时动态更新事件的原型定义.

However, when the message is of type github.com/golang/protobuf/ptypes/any.Any the options are nil. How can I retrieve the event_name from the message? I've come across the protoregistry.MessageTypeResolver, which looks like it might help, but I would need to figure out a way to dynamically update the proto definitions of the events when clients integrate.

推荐答案

为了获得 Any 类型的选项,您需要其特定的 protoreflect.MessageType 您可以将其解组为特定的消息.为了获取消息类型,您需要一个 MessageTypeResolver .

In order to obtain the options of an Any type, you need its specific protoreflect.MessageType so that you can unmarshal it into a specific message. In order to get the message type, you need a MessageTypeResolver.

任何包含一个 type_url 字段,该字段可用于该目的.为了将 Any 对象解组为现有消息类型的消息:

Any contains a type_url field, which can be used for that purpose. In order to unmarshal the Any object into a message of an existing message type:

// GlobalTypes contains information about the proto message types
var res protoregistry.MessageTypeResolver = protoregistry.GlobalTypes
typeUrl := anyObject.GetTypeUrl()
msgType, _ := res.FindMessageByURL(typeUrl)

msg := msgType.New().Interface()
unmarshalOptions := proto.UnmarshalOptions{Resolver: res}
unmarshalOptions.Unmarshal(anyObject.GetValue(), msg)

收到特定消息后,您只需获得所需的选项即可:

After having the specific message, you can simply get the option you need:

msgOpts := msg.ProtoReflect().Descriptor().Options()
eventName := proto.GetExtension(msgOpts, mypackage.E_EventName)

请注意,如果消息未扩展 event_name 选项,并且需要恢复该消息,则 proto.GetExtension 会惊慌.可以在函数的开头添加该块:

Note that proto.GetExtension will panic if the message doesn't extend the event_name option, and it needs to be recovered. This block can be added at the beginning of the function:

defer func() {
    if r := recover(); r != nil {
        // err is a named return parameter of the outer function
        err = fmt.Errorf("recovering from panic while extracting event_name from proto message: %s", r)
    }
}()

请注意,应用程序必须导入包含原型定义的包,以便 protoregistry.GlobalTypes 识别类型.您可以在代码中执行以下操作:

Note that the application has to import the package containing the proto definitions in order for protoregistry.GlobalTypes to recognize the type. You could do something like this in your code:

var _ mypackage.SomeEvent

这篇关于Go中Any类型消息的自定义protobuf选项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆