在 Go 中使用 typeURL 创建原型的空实例

问题描述 投票:0回答:1

我正在尝试在给定 typeURL 的 Go 中生成原型实例。基本上我想做的是模式验证。我有一条原始消息发送到 gRPC 服务,该消息有一个字段,即 protobuf.Any。现在“Any”包含我使用 option go_package 指定的“typeUrl”(并且我已经验证它是正确的),以及“Value”,它是包含我需要的数据的编组原型的字节数组。

我想做的是,当我在服务器端收到请求时,我想使用“typeUrl”生成“Value”中包含的原型的空实例。下面是我的代码:

func NewProtoInstanceFromAny(any *anypb.Any) (protoreflect.ProtoMessage, error) {
typeURL := any.TypeUrl
// Parse the TypeURL to get the package name and message name
segments := strings.Split(typeURL, "/")
packageName := segments[0]
messageName := segments[1]
println(messageName)
println(packageName)
messageType, _ := protoregistry.GlobalTypes.FindMessageByName(protoreflect.FullName(packageName + "." + messageName))
if messageType == nil {
    print("YES")
    return nil, fmt.Errorf("message %s not found in package %s", messageName, packageName)
}

newValue := messageType.New().Interface()
// Unmarshal the value field of the Any proto into the new message instance
println("HEY")
if err := protojson.Unmarshal(any.Value, newValue); err != nil {
    return nil, err
}

print("STRING" + newValue.ProtoReflect().Descriptor().FullName())

问题是我的 messageType 为 nil,这可能意味着在“GlobalRegistry”中找不到该文件。所以我想我的问题是,如何将原型添加到注册表中?我正在玩 protoregistry.Files{} 但似乎无法弄清楚。这是我在网上找到的一个例子,但它不适用于我的情况:

protoFile, err := ioutil.ReadFile("path/to/file/test.proto")
if err != nil {
    print(err)
}

pbSet := new(descriptorpb.FileDescriptorSet)
if err := proto.Unmarshal(protoFile, pbSet); err != nil {
    print(err)
}

pb := pbSet.GetFile()

// Initialize the file descriptor object.
fd, err := protodesc.NewFile(pb[0], protoregistry.GlobalFiles)
if err != nil {
    print(err)
}

// and finally register it.
err = protoregistry.GlobalFiles.RegisterFile(fd)
if err != nil {
    print(err)
}

由于某种原因,此代码因索引超出范围而发生恐慌。希望得到一些帮助!

go protocol-buffers file-descriptor
1个回答
0
投票

解决方案

您需要导入包含生成的

.pb.go
文件的包。因此,如果原始文件是
path/to/foo.proto
并且生成的文件是
path/to/foo/foo.pb.go
,那么一个简单的导入语句就足够了。

import _ "path/to/foo"

原因

消息在生成文件的

init
函数中注册到全局注册表中。
init
函数创建一个类型生成器并调用其
Build
方法。在此函数中,有点复杂,但您可以看到类型及其描述符已在全局注册表中注册。这是相关的源代码

© www.soinside.com 2019 - 2024. All rights reserved.