How to encode a repeated google.protobuf.any?

1k Views Asked by At

I have a message and I would like to package it into an any repeated google proto type:: Is there a way to encode an repeated any message type?

Can I even use repeated tag with google.protobuf.any?

message Onesensor{
    string name=1
    string type=2
    int32_t reading=3
}


/** Any Message **/
message RepeatedAny{
repeated google.protobuf.any sensors = 1;
}

I am looking for an example, currently using nanopb to encode.

2

There are 2 best solutions below

0
On

Sure, it is just a regular message.

https://github.com/nanopb/nanopb/tree/master/tests/any_type shows how to encode a single Any message, encoding many is like encoding any array. You'll have a choice between allocating statically, allocating dynamically or using callbacks. Or you can just encode a single subfield at a time into output stream, because concatenating encoded concatenates arrays in protobuf format.

0
On

I think I found my issue, I cannot use(repeated tag on the google.protobuf.any, as I would like to append the RepeatedAny messages in the final binary):

message Onesensor{
    string name=1
    string type=2
    int32_t reading=3
}

message RepeatedAny{
repeated google.protobuf.any sensors = 1;
}

Instead I should use something like this:

message Onesensor{
    string name=1
    string type=2
    int32_t reading=3
}

message SensorAny{
google.protobuf.any sensor = 1;
}

message RepeatedAny{
repeated SensorAny sensors = 1;
}

I should not use the repeated tag on the google.protobuf.any, I should be using it on a message that contains the google.protobuf.any instead, so that the protobinary can contain the format (sensors1), (sensors2).....(sensorsN), one or more SensorAny messages.

Below is the sample code, if someone finds this question in the future for nanopb:

    /* First encode the SensorAny message by setting the value of the first field,
       The first field of this message is of type google.protobuf.any, so it should have
       1. sensor.type_url
       2. sensor.value
    */

    void* pBufAny = calloc(1, sBufSize);
    pb_ostream_t ostream_any = pb_ostream_from_buffer(pBufAny, sBufSize);
    SensorAny SensorAnyProto = SensorAny_init_default;
    SensorAnyProto.has_message = true;
    SensorAnyProto.sensor.type_url.arg = "type.googleapis.com/SensorAny.proto";
    SensorAnyProto.sensor.type_url.funcs.encode = Proto_encode_string;
    ProtoEncodeBufferInfo_t BufInfo = {
            .Buffer = pBuf, /* I have already filled and encoded Onesensor message previously as pBuf */
            .BufferSize = ostream.bytes_written,
    };
    SensorAnyProto.sensor.value.funcs.encode = Proto_encode_buffer;
    SensorAnyProto.sensor.value.arg = &BufInfo;
    pb_encode(&ostream_any, SensorAny_fields, &SensorAnyProto);
    free(pBuf);


    // Now Use the above encoded Any message buffer pBufAny to set the first repeated field in RepeatedAny

    RepeatedAny SensorAnyRepeated = RepeatedAny_init_default;
    ProtoEncodeBufferInfo_t AnyBufInfo = {
            .Buffer = pBufAny,
            .BufferSize = ostream_any.bytes_written,
    };

    AnyRepeated.sensors.arg=&AnyBufInfo;
    AnyRepeated.sensors.funcs.encode = Proto_encode_buffer;

    void* pBufAnyRepeated = calloc(1, sBufSize);
    pb_ostream_t ostream_repeated = pb_ostream_from_buffer(pBufAnyRepeated, sBufSize);
    !pb_encode(&ostream_repeated, RepeatedAny_fields, &AnyRepeated);
    free(pBufAny);