如何在没有模式的情况下从 protobuf 消息中提取字段
How to extract field from protobuf message without schema
根据 this issue, the protoreflect 包提供了用于访问 protobuf 消息的“未知字段”的 API,但如果没有任何现有模式,我看不到任何使用它的方法。基本上,我想执行“弱解码”,类似于 JSON 解组器在输出类型为 map[string]interface{}
.
时所做的事情
the documentation 中的示例如下所示:
err := UnmarshalOptions{DiscardUnknown: true}.Unmarshal(b, m)
其中 b
是输入字节切片,m
是输出消息,需要以某种方式初始化,如您所见 . I was thinking that dynamicpb can be used for this purpose, but it doesn't look possible without having an existing MessageDescriptor,这就是我被卡住的地方。 ..
我能够使用原始模式中的低级别 protowire package. Here is a full example, where I extract two fields of type uint64
(which happen to be assigned field numbers 4 和 5 实现此目的):
import "google.golang.org/protobuf/encoding/protowire"
func getData(src []byte) (creationTime, expiryTime uint64, err error) {
remaining := src
for len(remaining) > 0 {
fieldNum, wireType, n := protowire.ConsumeTag(remaining)
if n < 0 {
return 0, 0, fmt.Errorf("failed to consume tag: %w", protowire.ParseError(n))
}
remaining = remaining[n:]
switch fieldNum {
case 4: // Expiry time
if wireType != protowire.VarintType {
return 0, 0, fmt.Errorf("unexpected type for expiry time field: %d", wireType)
}
expiryTime, n = protowire.ConsumeVarint(remaining)
case 5: // Creation time
if wireType != protowire.VarintType {
return 0, 0, fmt.Errorf("unexpected type for creation time field: %d", wireType)
}
creationTime, n = protowire.ConsumeVarint(remaining)
default:
n = protowire.ConsumeFieldValue(fieldNum, wireType, remaining)
}
if n < 0 {
return 0, 0, fmt.Errorf("failed to consume value for field %d: %w", fieldNum, protowire.ParseError(n))
}
remaining = remaining[n:]
}
return
}
根据 this issue, the protoreflect 包提供了用于访问 protobuf 消息的“未知字段”的 API,但如果没有任何现有模式,我看不到任何使用它的方法。基本上,我想执行“弱解码”,类似于 JSON 解组器在输出类型为 map[string]interface{}
.
the documentation 中的示例如下所示:
err := UnmarshalOptions{DiscardUnknown: true}.Unmarshal(b, m)
其中 b
是输入字节切片,m
是输出消息,需要以某种方式初始化,如您所见
我能够使用原始模式中的低级别 protowire package. Here is a full example, where I extract two fields of type uint64
(which happen to be assigned field numbers 4 和 5 实现此目的):
import "google.golang.org/protobuf/encoding/protowire"
func getData(src []byte) (creationTime, expiryTime uint64, err error) {
remaining := src
for len(remaining) > 0 {
fieldNum, wireType, n := protowire.ConsumeTag(remaining)
if n < 0 {
return 0, 0, fmt.Errorf("failed to consume tag: %w", protowire.ParseError(n))
}
remaining = remaining[n:]
switch fieldNum {
case 4: // Expiry time
if wireType != protowire.VarintType {
return 0, 0, fmt.Errorf("unexpected type for expiry time field: %d", wireType)
}
expiryTime, n = protowire.ConsumeVarint(remaining)
case 5: // Creation time
if wireType != protowire.VarintType {
return 0, 0, fmt.Errorf("unexpected type for creation time field: %d", wireType)
}
creationTime, n = protowire.ConsumeVarint(remaining)
default:
n = protowire.ConsumeFieldValue(fieldNum, wireType, remaining)
}
if n < 0 {
return 0, 0, fmt.Errorf("failed to consume value for field %d: %w", fieldNum, protowire.ParseError(n))
}
remaining = remaining[n:]
}
return
}