LINUX.ORG.RU

Общая функция для парсинга всех сообщений protobuf

 ,


0

1

имеется протокол

package ru.cow.moo;

message Message1 {
    string Id = 1;
    int32 code = 2;
}

message Message2 { ...

Каким-то образом получены строки foo и bar, например отсылающая сторона из запаковала и прислала

std::string foo, bar;
int foo_id = 1, bar_id = 2;
moo::Message1 m1;
m1.set_id("123");
m1.set_code(1);
m1.SerializeToString(&foo);
...

Как написать единую функцию ParseMessage, которая распарсит строку и вернет сообщение в соответсвии с его id

moo::Message1 m1 = ParseMessage(foo, foo_id);
moo::Message2 m2 = ParseMessage(bar, bar_id);
???

P.S. далее вот этого, что не вытянул

void ParseMessage(const std::string & data, int i, google::protobuf::Message* mess) {
    switch (i) {
        case 1:
            mess->ParseFromString(data);
            mess->PrintDebugString();
            // other actions
        // case 2:
    }
}


google::protobuf::Message *m = new moo::Message1;
ParseMessage(foo, 1, m);
std::cout << "id = " << static_cast<moo::Message1*>(m)->id() << std::endl;
delete m;

package ru.cow.moo;

message Message1 {
    int32 code = 2;
}

message Message2 { ... }
....
message MessageHolder {
    int32 Id = 1;
    bytes MessagePacked = 2;
}

или

package ru.cow.moo;

message Message1 {
    int32 code = 2;
}

message Message2 { ... }
....
message MessageHolder {
    oneof MessageUnion {
        Message1 mess1 = 1;
        Message2 mess2 = 2;
    }

}
ossa ★★ ()
Последнее исправление: ossa (всего исправлений: 2)
Ответ на: комментарий от ossa

oneof MessageUnion

спасибо!

На ++ похоже правильно это шаблонами делать, вот как то так

template<class T> void Parse(const std::string & data, T & t) 
{ 
  // … some actions 
  t.ParseFromString(data); 
} 

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

На ++ похоже правильно это шаблонами делать, вот как то так

Да, если у тебя тип сообщения известен уже. oneof как раз может содержать один из известных типов, соответственно ты можешь проверить что там пришло и получить сообщение.

В первом варианте, который с bytes, можно самому запаковать нужное сообщение и установить id. Может пригодится, если у тебя сам MessageHolder используется как транспорт и сообщения заранее могут быть неизвестны. У протобуфера есть еще Any. https://developers.google.com/protocol-buffers/docs/proto3#any Тоже может быть полезна. Но это от задачи твоей зависит.

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

мне нужно всего лишь распарсить принятое сообщение, id которого известно. Я хочу написать один парсер для всех сообщений (он делает одинаковые проверки и затем собирает протобуфный класс из байтиков в строке). Сообщений очень много ... за 100.

С шаблонноей функцией все Ок. Интересно, а без шаблонов это реально??

string mess = ...;
moo::Message1 = Parse(mess, 1);

вот чуть-чуть чего-та не хватает

ЧТОТО Parse(std::string m, int id) {
   // ... действия всякие
   if (id == 1) {
     moo::Message1 res;
     res.ParseFromString(m);
     res.PrintDebugString();
     return res;
   }
   if (id == 2) {
     moo::Message2 res;
     res.ParseFromString(m);
     res.PrintDebugString();
     return res;
   }
   // ...:w
}

cvprog ()
Последнее исправление: cvprog (всего исправлений: 1)
Ответ на: комментарий от cvprog
ЧТОТО Parse(std::string m, int id) {

std::variant если сообщения известны. Ну или передавать шаблон, как сделал уже.

template<class T> T Parse(const std::string & data) 
{ 
  // … some actions 
  T t;
  t.ParseFromString(data);
  return t; 
} 
ossa ★★ ()
Ответ на: комментарий от ossa

std::variant

Спасибо, огромное! Это то, что я искал ) Нужно учить матчасть.

class A {
public:
    void Recive() {
        moo::Message1 m1;
        m1.set_id("123");
        m1.set_code(1);
        m1.SerializeToString(&currentMessage);
    }
    std::variant<moo::Message1, moo::Message2> Parse(int id) {
        if (id == 1) {
            moo::Message1 mess1;
            mess1.ParseFromString(currentMessage);
            return mess1;
        }
    }
private:
    std::string currentMessage {""};
};
A a;
a.Recive();
auto res = a.Parse(1);
moo::Message1 m1 = std::get<moo::Message1>(res);
cvprog ()
Ограничение на отправку комментариев: только для зарегистрированных пользователей