I have the need to define proto fields of a message on runtime and send data along with them. So what I've done is I've defined them on runtime using FieldDescriptorProto
and send it from server to client.
My proto file looks like this:
syntax = "proto3";
import "google/protobuf/descriptor.proto";
package handshake;
option cc_enable_arenas = true;
message ProtoRequest {
google.protobuf.FileDescriptorProto custom_proto = 1;
}
service HandShake {
rpc sendProto (ProtoRequest) returns (ProtoResponse) {}
}
message ProtoResponse {
bool received = 1;
}
what I did is I defined the fields and set values to them in the server-side, something like this:
// --- server ---
// assume all fields are int64
const google::protobuf::Message* message = factory.GetPrototype(message_desc);
google::protobuf::Message* mutable_msg = message->New(&arena);
const Reflection* reflection = mutable_msg->GetReflection();
const Descriptor* descriptor = mutable_msg->GetDescriptor();
for (int i = 0; i < descriptor->field_count(); i++) {
const FieldDescriptor * fd = descriptor->field(i);
reflection->SetInt64(mutable_msg,fd,i);
}
// verification
for (int i = 0; i < descriptor->field_count(); i++) {
const FieldDescriptor* fd = descriptor->field(i);
// reflection->SetInt64(mutable_msg, fd, i);
cout << fd->name() << " -> " << reflection->GetInt64(*mutable_msg, fd) << endl;
}
I verify if the values are set on the server-side and it was good. But When I transfer the FileDescriptor
to the client:
// --- client ---
FileDescriptorProto local_proto = request->custom_proto(); //this is from the server
//const google::protobuf::Descriptor* message_desc = local_proto.GetDescriptor();
DescriptorPool pool_;
const FileDescriptor* local_proto_;
local_proto_ = pool_.BuildFile(local_proto);
// display message contents
const google::protobuf::Descriptor* message_desc = local_proto_->FindMessageTypeByName("AttribRow");
cout << "Field Count: " << message_desc->field_count() << endl;
google::protobuf::DynamicMessageFactory factory;
const google::protobuf::Message* mutable_msg = factory.GetPrototype(message_desc);
const Reflection* reflection = mutable_msg->GetReflection();
const Descriptor* descriptor = mutable_msg->GetDescriptor();
for (int i = 0; i < descriptor->field_count(); i++) {
const FieldDescriptor* fd = descriptor->field(i);
cout << fd->name() << " -> " << reflection->GetInt64(*mutable_msg, fd) << endl; //this fails
}
When I verify if I received the data successfully on the client side, all the fields are set to 0 (default value of the datatype).
So what I need in simple words is, I want to transfer data as protobuf, whose field names I know only at runtime. So I should be defining proto fields for those and transfer data along with them from server to client successfully.