Parse nested (opaque, any-typed) Protobuf message - protocol-buffers

I have a message envelope:
import "google/protobuf/any.proto";
message Envelope {
string type = 1;
int32 version = 2;
string message_id = 5;
string timestamp = 6;
google.protobuf.Any message = 7;
}
Now, I happen to know that the message is another Protobuf value with the following type:
And a message defined as follows:
message Message {
int32 value = 1;
string name = 2;
}
Is it possible for me to do a one-shot parsing of this combined message? I am thinking that the problem with substituting Any with Message is the field numbering.

Any is just:
message Any {
string type_url = 1;
bytes value = 2;
}
where the value is just the regular payload content. If you know that the type is your Message, then you can use instead
message Envelope {
string type = 1;
int32 version = 2;
string message_id = 5;
string timestamp = 6;
FakeAny message = 7;
}
message FakeAny {
// don't even need to capture the type_url
Message value = 2;
}
message Message {
int32 value = 1;
string name = 2;
}
and it should deserialize directly.

Related

Reusing Message in the same package in multiple files

Is there a way to reuse protobuf structs across multiple proto files?
in the client.proto file I have the following
message SingleOperation {
string command = 1;
}
message ClientBatch {
string unique_id = 1;
repeated SingleOperation requests = 2;
int64 sender = 3;
}
Then in network.proto file, I have the following
message MemPool {
int32 sender = 1;
string unique_id = 2;
SingleOperation op = 3;
}
In the network.proto file, I need to reuse the SingleOperation message.
However, I do not see an option to do this.
Does protobuff support some sort of packaging to support struct reuse?

How to represent a mix of enum and oneof in protobuf

I am trying to create a protocol buffer message with fields that are either a message or one of a choice of some constant (like an enum). Something that is logically equivalent to:
message Error {
oneof error_type {
EMPTY_METHOD_NAME = 0
ExecutionError execution_error = 1;
}
message ExecutionError {
string value = 1;
}
}
Essentially, I would like a field that can represent either an error type that is just a name with no fields, or an error type that has fields. How would I do this with protobuf3?
See Enumerations in the Language Guide (proto3)
message Error {
oneof error_type {
Foo foo = 1;
ExecutionError execution_error = 2;
}
enum Foo {
X = 0;
Y = 1;
Z = 2;
}
message ExecutionError {
string value = 1;
}
}

Protocol buffer split oneof message to a different file

I use nanopb and a .proto file that looks like this (simplified):
syntax = "proto3";
message Type1
{
bool a = 1;
}
message Type2
{
int32 b = 1;
}
message Message
{
int32 id = 1;
oneof oneMessage {
Type1 messageType1 = 2;
Type2 messageType2 = 3;
}
}
I now need to split the oneMessage to a different .proto file and import it. I can do something like:
file a.proto:
syntax = "proto3";
import "b.proto"
message Message
{
int32 id = 1;
oneofTypeMessage aMessage = 2;
}
file b.proto
syntax = "proto3";
message Type1
{
bool a = 1;
}
message Type2
{
int32 b = 1;
}
message oneofTypeMessage
{
oneof oneMessage {
Type1 messageType1 = 2;
Type2 messageType2 = 3;
}
}
But this means I can't get to my message types with message.messageType1, triggering lots of changes in the existing source code. How can I split the oneof part to another file without changing the way I access to it?
I've tried declaring Message in both files but it is not permitted.
No. oneMessage is not a message type, and to import something from another file, it must be a message type. Adding a new oneofTypeMessage would add an additional node in the graph, and would not be data-compatible with the original data.
You can move Type1 and Type2, but the oneof must stay as-was; so: this is valid:
file a.proto:
syntax = "proto3";
import "b.proto"
message Message
{
int32 id = 1;
oneof oneMessage {
Type1 messageType1 = 2;
Type2 messageType2 = 3;
}
}
file b.proto:
syntax = "proto3";
message Type1
{
bool a = 1;
}
message Type2
{
int32 b = 1;
}

How do I assign value to a repeated oneof field in a protobuf message?

I have a protobuf message CoverageReport like this:
message Deductible {
double amount = 1;
string currency = 2;
}
message Insurance{
string type = 1;
string policyNumber = 2;
string agreementName = 3;
string appliedTo = 4;
string validFrom = 5;
string validTo = 6;
Deductible deductible = 7;
}
message Warranty {
string type = 1;
string warrantyType = 2;
string agreementName = 3;
string appliedTo = 4;
string validFrom = 5;
string validTo = 6;
}
message Coverage {
oneof item {
Insurance insurance = 1;
Warranty warranty = 2;
}
}
message CoverageReport {
bool coverageAppliance = 1;
repeated Coverage coverages = 2;
}
In my program I'm trying to assign values to a message instance, but I'm not sure how to assign to the oneof field Coverage which should then be appended to Coverages, like this
I get a response from an api, which i unmarshal into the struct CoverageReport which has similar structure to the protobuf. Then i need to create a protobuf message using the values from the struct. But it doesn't seem to work to asssign to the one of field!
type CoverageReport struct {
CoverageAppliance string `json:"coverageAppliance"`
Coverages []struct {
Type string `json:"type"`
PolicyNumber string `json:"policyNumber,omitempty"`
AgreementName string `json:"agreementName"`
AppliedTo string `json:"appliedTo"`
ValidFrom string `json:"validFrom"`
ValidTo string `json:"validTo"`
Deductible struct {
Amount float64 `json:"amount"`
Currency string `json:"currency"`
} `json:"deductible,omitempty"`
WarrantyType string `json:"warrantyType,omitempty"`
} `json:"coverages"`
}
var coveragereport *CoverageReport
err = json.Unmarshal(body, &coveragereport)
var cr *vcsproto.CoverageReport
if coveragereport.CoverageAppliance == "Yes" {
cr.CoverageAppliance = true
}
for _, item := range coveragereport.Coverages {
if item.Type == "Warranty"{
var warranty *vcsproto.Warranty
warranty.Type = item.Type
warranty.WarrantyType = item.WarrantyType
warranty.AgreementName = item.AgreementName
warranty.AppliedTo = item.AppliedTo
warranty.ValidFrom = item.ValidFrom
warranty.ValidTo = item.ValidTo
var coverage *vcsproto.Coverage
coverage.Item.Warranty = warranty
cr.Coverages = append(cr.Coverages, coverage)
} else {
var insurance *vcsproto.Insurance
insurance.Type = item.Type
insurance.PolicyNumber = item.PolicyNumber
insurance.AgreementName = item.AgreementName
insurance.AppliedTo = item.AppliedTo
insurance.ValidFrom = item.ValidFrom
insurance.ValidTo = item.ValidTo.
insurance.Deductible.Currency = item.Deductible.Currency
insurance.Deductible.Amount = item.Deductible.Amount
var coverage *vcsproto.Coverage
coverage.Item.Insurance = Insurance
cr.Coverages = append(cr.Coverages, coverage)
}
}
Take a look in the generated code here.
You do not assign directly to the Warranty nor Insurance subfields, but directly to the Item field. so coverage.Item = {insurance/warranty} should work.
Also note that in your code you're assigning coverage.Item.Insurance = Insurance - you probably meant the second Insurance to be the variable insurance instead.

How to define empty parameter for Protocol Buffers rpc method?

I have a method that I would like defined called FindAll which requires no parameters. ProtoC is complaining.
Expected type name.
This is for line:
rpc findAll () returns (BenchmarksList);
syntax = "proto3";
package helloWorldGRPC;
service HelloWorldGRPCService {
rpc findById (BenchmarksById) returns (Benchmarks);
rpc findAll () returns (BenchmarksList);
}
message BenchmarksById {
string id = 1;
}
message BenchmarksList {
repeated Benchmarks benchmarks = 1;
}
message Benchmarks {
string trans_id = 1;
string protocol = 2;
string database = 3;
string updated_at = 4;
string created_at = 5;
repeated Action actions = 6;
}
message Action {
string trans_id = 1;
int32 payload_length = 2;
string payload = 3;
string status = 4;
string updated_at = 5;
string created_at = 6;
}
The preferred way is to pass Empty - as tooling may recognize and optimize for that scenario. But in reality, there is nothing "special" about that type and any message - empty or otherwise - will suffice.

Resources