Home > Backend Development > Golang > How to Unmarshal Unknown Protobuf Messages in Go?

How to Unmarshal Unknown Protobuf Messages in Go?

Linda Hamilton
Release: 2024-12-03 02:15:10
Original
761 people have browsed it

How to Unmarshal Unknown Protobuf Messages in Go?

Unmarshaling Unknown Protobuf Messages in Go

Unmarshalling protobuf messages into an interface{} to facilitate type casting is not feasible as the proto.Unmarshal function expects an argument of type proto.Message, an interface that concrete protobuf types implement.

Alternative Approach with Known Metadata

In cases where at least some contextual information (e.g., a string or number) accompanies the byte slice, you can use that information to map to the expected protobuf type and instantiate it before passing it to proto.Unmarshal:

func decodeWithMetadata(data []byte, identifier string) error {
    var message proto.Message
    switch identifier {
        case "foo":
            message = &mypb.Foo{}
        case "bar":
            message = &mypb.Bar{}
    }
    if err := proto.Unmarshal(data, message); err != nil {
        return err
    }
    log.Printf("%v\n", data)
    return nil
}
Copy after login

Parsing Completely Unknown Payloads

However, if the byte payload is entirely unknown, consider the protowire package, which allows extracting limited information from wire-formatted protobuf messages. Keep in mind that the wire representation of protobuf messages is ambiguous, leading to weak semantics.

Parser Implementation

The following code parses unknown protobuf messages:

type Field struct {
    Tag Tag
    Val Val
}

type Tag struct {
    Num int32
    Type protowire.Type
}

type Val struct {
    Payload interface{}
    Length int
}

func parseUnknown(b []byte) []Field {
    // ... implementation to parse unknown protobuf messages as described in the provided answer ...
}
Copy after login

Sample Usage

Given a protobuf schema like:

message Foo {
  string a = 1;
  string b = 2;
  Bar bar = 3;
}

message Bar {
  string c = 1;
}
Copy after login

The following code demonstrates how to use the parser:

// Parse the protobuf message as byte slice
b := []byte{0x0a, 0x01, 0x41, 0x12, 0x01, 0x42, 0x1a, 0x03, 0x43}
fields := parseUnknown(b)
for _, field := range fields {
    fmt.Printf("%#v\n", field)
}
Copy after login

Output:

main.Field{Tag:main.Tag{Num:1, Type:2}, Val:main.Val{Payload:[]uint8{0x41}, Length:1}}
main.Field{Tag:main.Tag{Num:2, Type:2}, Val:main.Val{Payload:[]uint8{0x42}, Length:1}}
main.Field{Tag:main.Tag{Num:1, Type:2}, Val:main.Val{Payload:[]uint8{0x43}, Length:1}}
main.Field{Tag:main.Tag{Num:3, Type:2}, Val:main.Val{Payload:[]main.Field{main.Field{Tag:main.Tag{Num:1, Type:2}, Val:main.Val{Payload:[]uint8{0x43}, Length:1}}}, Length:3}}
Copy after login

The above is the detailed content of How to Unmarshal Unknown Protobuf Messages in Go?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template