为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用 github.com/jhump/protoreflect 解析知道消息描述符

如何使用 github.com/jhump/protoreflect 解析知道消息描述符

Go
LEATH 2023-07-04 16:54:37
我有一个文件,其中包含以下原始消息的字节片段。syntax = "proto3";package main;message Address {    string street = 1;    string country = 2;    string state = 3;}我的消息类型描述如下:func GetProtoDescriptor() (*descriptor.DescriptorProto, error) {    return &descriptor.DescriptorProto{        Name: proto.String("Address"),        Field: []*descriptor.FieldDescriptorProto{            &descriptor.FieldDescriptorProto{                Name:     proto.String("street"),                JsonName: proto.String("street"),                Number:   proto.Int(1),                Label:    descriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),                Type:     descriptor.FieldDescriptorProto_TYPE_STRING.Enum(),            },            &descriptor.FieldDescriptorProto{                Name:     proto.String("state"),                JsonName: proto.String("state"),                Number:   proto.Int(2),                Label:    descriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),                Type:     descriptor.FieldDescriptorProto_TYPE_STRING.Enum(),            },            &descriptor.FieldDescriptorProto{                Name:     proto.String("country"),                JsonName: proto.String("country"),                Number:   proto.Int(2),                Label:    descriptor.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),                Type:     descriptor.FieldDescriptorProto_TYPE_STRING.Enum(),            },        },    }, nil}我想知道如何最好地使用jhump/protoreflect使用上面的消息描述符来解析文件的内容。感谢您的帮助。
查看完整描述

1 回答

?
慕森王

TA贡献1777条经验 获得超3个赞

典型的方法是使用以下命令将协议编译protoc为 Go 代码:

protoc main.proto --go_out=.

这将生成main.pb.go,其类型称为Address

var addr Address
err := proto.Unmarshal(bytes, &addr)

如果由于某种原因这是不可能的(例如,您必须使用描述符动态地执行此操作),那么还有其他选择。(但情况要复杂得多。)

  1. 使用protoc生成的描述符。您可以protoc导出到描述符文件(通过-o标志)。如果这是用于 RPC,请让服务器使用服务器反射;然后,您可以使用github.com/jhump/protoreflect/grpcreflect包下载服务器的描述符(大概由 生成protoc)。

  2. 如果您必须以编程方式创建描述符,而不是使用protoc,我建议使用github.com/jhump/protoreflect/desc/builder包来构造它(而不是尝试手动创建原始原型)。例如,您的原始原型是不够的,因为它们没有parent FileDescriptorProto,它是任何描述符层次结构的根。该构建器包可以为您处理类似的细节(例如,如果需要,它将合成父文件描述符)。

无论如何,您想要的描述符是 a desc.Descriptor(来自github.com/jhump/protoreflect/desc包)。上面的提示(使用其他 protoreflect 子包)将返回desc.Descriptor实例。如果您只有原始描述符原型(如示例代码中所示),您需要首先使用desc#CreateFileDescriptor*descriptor.FileDescriptorProto函数将其转换为 a 。*desc.FileDescriptor

如果您正在使用protoc及其-o选项来创建描述符集文件(也不要忘记标志),您可以使用desc#CreateFileDescriptorFromSet--include_imports函数加载它并将其转换为描述符集文件。这是一个例子:*desc.FileDescriptor

bytes, err := ioutil.ReadFile("protoset-from-protoc")

if err != nil {

  panic(err)

}

var fileSet descriptor.FileDescriptorSet

if err := proto.Unmarshal(bytes, &fileSet); err != nil {

  panic(err)

}

fd, err := desc.CreateFileDescriptorFromSet(&fileSet)

if err != nil {

  panic(err)

}

// Now you have a *desc.FileDescriptor in `fd`

一旦有了正确的描述符,您就可以创建一个*dynamic.Message。然后,您可以使用该proto#Unmarshal函数或使用动态消息的Unmarshal方法对其进行解组。


查看完整回答
反对 回复 2023-07-04
  • 1 回答
  • 0 关注
  • 113 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信