LINUX.ORG.RU

присвоить одинаковые message из разных протоколов protobuf в C++

 ,


0

4

Есть протокол 1

package ru.cow.moo;
message Message1 {
    string Id = 1;
    int32 code = 2;
    # очень много полей далее
}

и другой протокол 2, использующий Message1 точно такое же как в протоколе 1

package ru.dog.woof;
message Message1 {
    string Id = 1;
    int32 code = 2;
    # очень много полей далее
}

Прилетело сообщение из первого протокола типа Message1

ru::cow::moo::Message1 cow_mess1;
cow_mess1.set_id("123");
cow_mess1.set_code(1);
// туча полей

Как можно просто привести сообщение с одинаковыми полями из одного протокола в другой без перебора всех полей?

ru::dog::woof::Message1 gav_mess1;
gav_mess1 = protobuf_cast<ru::dog::woof::Message1>(cow_mess1); // ???


struct Message1 {
  std::string id;
  int code;
};

struct Message2 {
  std::string id;
  int code;
};

Message1 m1;
Message2 m2 = struct_cast<Message1>(m1);

Какие есть механизмы в С++, чтобы реализовать шаблон функцию struct_cast?

Begemoth ★★★★★
()
Последнее исправление: Begemoth (всего исправлений: 1)

Это не безопасно и такого способа быть не должно. Сделай чтобы это было одно сообщение. Если так сделать нельзя значит это разные сообщения которые совпадают по чистой случайности и могут завтра измениться в разные стороны несовместимым образом. Но вообще можно сериализовать в строку одно и сразу десериализовать из неё другое.

slovazap ★★★★★
()

Не знаю как в Ссях, но в общем случае protobuf ничего не знает про messages. Пока оно сходится по тэгам, оно совместимо. Тэги можно пропускать. Т.е.

message X {
    int32 id = 1;
    string text = 2;
}

и

message Y {
     int32 id = 1;
     bytes blob = 3;
}

в общем случае совместимы. Можно делать прикольные вещи, если копнуть глубже.

TL;DR: де-маршалишь одно сообщение в другое, главное попасть по тэгам в типы. Оно в принципе так и задумывалось.

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 3)
Ответ на: комментарий от slovazap

Да, спасибо, классно! Через строку работает

ru::cow::moo::Message1 cow_mess1;
// ...
std::string data ;
cow_mess1.SerializeToString(&data);
ru::dog::woof::Message1 gav_mess1;
gav_mess1.ParseFromString(data);
Если поменяется протокол, то можно проверку поставить - ParseFromString упадет.

Но, по смыслу, мне нужно будет адаптировать протокол 2 (ru::dog::woof::Message1) под протокол 1 (ru::cow::moo::Message1): как бы Message1 являтся просто транзитным сообщением, которое я могу передавать не читая. Но, светить протокол 1 я не могу (только вот это Message1 отображаю в протоколе 2). Может можно как то более искустно заюзать протобуфер и сделать Message1 общим?

cvprog
() автор топика
Ответ на: комментарий от slovazap

Совсем по-хорошему сервер предоставляет свой message, а клиенты как хотят читают свои. Т.е. разделение на server/client protfiles. Главное только, чтобы tag = type совпали, а то билиберда выйдет.

beastie ★★★★★
()
Ответ на: комментарий от beastie

Ничего хорошего тут конечно же нет. Клиенты должны не «как хотят» читать белиберду, а читать конкретный централизовано определённый протокол.

slovazap ★★★★★
()
Ответ на: комментарий от cvprog

Ничего не понял из того что вы хотите. Общим Message1 делается тривиально - объявлением его один раз в одном файле. Потом инклудьте его куда хотите. А для транзитной передачи на транзитном узле вообще ничего не должно десеарелизовываться. Если при этом нужно передать какие-то поля нужные для доставки, то можно сделать так:

message TransitMessage {
    string recepient = 1;  // поле необходимое для доставки
    bytes data = 2;  // сериализованное что-то, с чем должны уметь работать только отправляющий и принимающий узлы, а транзитный ничего знать не обязан
}
slovazap ★★★★★
()
Ответ на: комментарий от slovazap

Таки нет. Попробую обьяснить. Сервер в общем случае не знает, что понадобится клиентам. Если совсем по фен-шую, то разделяют на серверный protobuf, и клиентские. Это взаимосвязанные, но раздельные файлы. Клиент сам себе выбирает только те поля в сообщении, в которых он заинтересован.

beastie ★★★★★
()
Ответ на: комментарий от beastie

Объяснить не получилось. Формат у них один из единого .proto файла, по другому быть не может. Чтобы взять и выстрелить себе в ногу разделив их нужно быть имбецилом.

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

нужно быть имбецилом

То-то всё не могу вспомнить, чем же ты заслужил свой комментарий:

slovazap ★★★★★ (04.11.20 14:19:34) Профнепригодная дурашка

Видимо из-за таких вот претенциозных заявлений. Ну да ладно. :D

из единого .proto файла, по другому быть не может

Надеюсь, ты понимаешь, что protobuf – языко-агностический формат бинарных данных. Т.е. у тебя сервер на java, клиент на rust и ещё один на python. Никак кроме форматом обмениваемых данных между собой не связанных. Одному нужен один набор сообщений, другому дрогой, а то и только часть сообщения.

И ты предлагаешь генерить всё из единой сырьевой базы, зашаренной между всеми? Ню-ню.

beastie ★★★★★
()
Ответ на: комментарий от beastie

Видимо из-за таких вот претенциозных заявлений. Ну да ладно. :D

Держи свои комплексы при себе. У меня про тебя тоже комментарий есть, и ты его подтверждаешь переходя с технического обсуждения на мою личность.

Т.е. у тебя сервер на java, клиент на rust и ещё один на python. Никак кроме форматом обмениваемых данных между собой не связанных.

И ты предлагаешь генерить всё из единой сырьевой базы, зашаренной между всеми?

Формат .proto от языка к языку не меняется, поэтому, представь себе, да - именно это я и предлагаю. Вообще, даже странно предлагать использовать инструмент так как он задумывался. Ты же сам написал что они связаны форматом сообщений. А ты их развязываешь, разделяя proto файлы. Выкидываешь механизмы сохранения совместимости заложенные в инструмент, дублируешь код. Ничего теперь тебя не спасёт от того чтобы добавить разные поля с одинаковыми тегами, или одинаковые с разными, или перепутать типы. Вот так делать - это и есть профнепригодность.

slovazap ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.