Go中Any类型消息的自定义protobuf选项 [英] Custom protobuf options of message of type Any in Go
问题描述
我有一个定义如下的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屋!