Протокол буферного полиморфизма - PullRequest
5 голосов
/ 11 августа 2010

У меня есть программа на C ++, которая отправляет различные события, например, StatusEvent и DetectionEvent с различными определениями прото-сообщений в службу сообщений (в настоящее время Active MQ, через APM activemq-cpp).Я хочу написать прослушиватель сообщений, который получает эти сообщения, анализирует их и записывает их в cout для целей отладки.Слушатель имеет status_event_pb.h и detection_event_pb.h связанный.

Мой вопрос: как я могу проанализировать полученное событие, не зная его типа?Я хочу сделать что-то вроде (в псевдокоде)

receive event
type = parseEventType(event);
if( type == events::StatusEventType) { 
    events::StatusEvent se = parseEvent(event);
    // do stuff with se
}
else {
    // handle the case when the event is a DetectionEvent
}

Я смотрел на этот вопрос , но я не уверен, что расширения - это правильный путь.Короткий фрагмент кода, указывающий путь, будет высоко ценится.Примеры по protobuf так редки!

Спасибо!


Кажется, расширения действительно подходят, но у меня есть еще один момент, который нужно прояснить.Вот предварительное определение, которое у меня есть до сих пор:

// A general event, can be thought as base Event class for other event types.
message Event {
    required int64 task_id = 1;     
    required string module_name = 2;    // module that sent the event

    extensions 100 to 199;               // for different event types
}

// Extend the base Event with additional types of events.
extend Event {
    optional StatusEvent statusEvent = 100;
    optional DetectionEvent detectionEvent = 101;
}

// Contains one bounding box detected in a video frame, 
// representing a region of interest.
message DetectionEvent {
    optional int64 frame = 2;   
    optional int64 time = 4;
    optional string label = 6;
}

// Indicate status change of current module to other modules in same service.
// In addition, parameter information that is to be used to other modules can
// be passed, e.g. the video frame dimensions.
message StatusEvent {
    enum EventType { 
        MODULE_START = 1; 
        MODULE_END = 2; 
        MODULE_FATAL = 3; 
    }
    required EventType type = 1;        
    required string module_name = 2;    // module that sent the event

    // Optional key-value pairs for data to be passed on.
    message Data {
        required string key = 1;
        required string value = 2;
    }
    repeated Data data = 3; 
}

Моя проблема сейчас заключается в том, чтобы (1) узнать, какое конкретное событие содержит сообщение о событии, и (2) убедиться, что оно содержит только одно такое событие (согласно определению оно может содержать как StatusEvent, так и DetectionEvent).

1 Ответ

3 голосов
/ 12 августа 2010

Я бы не использовал для этого буферы протокола, но, возможно, это сочетание малой полезности и других привычек.

В любом случае, я думаю, что я бы использовал здесь абстрактный класс для упрощения общей обработки и для сдерживания маршрутизации.Информация.Класс, который не будет определен с использованием protobuf и будет содержать сообщение с протоколом protobuf. * ​​1003 *

class Message
{
public:
  Type const& GetType() const;

  Origin const& GetOrigin() const;
  Destination const& GetDestination() const;

  // ... other informations

  template <class T>
  void GetContent(T& proto) const
  {
    proto.ParseFromIstream(&mContent); // perhaps a try/catch ?
  }

private:
  // ...

  std::stringstream mContent;
};

С этой структурой у вас есть общие и особые функции обработки на кончиках ваших пальцев:

void receive(Message const& message)
{
  LOG("receive - " << message.GetType() << " from " << message.GetOrigin()
                   << " to " << message.GetDestination());

  if (message.GetType() == "StatusEvent")
  {
    StatusEvent statusEvent;
    message.Decode(statusEvent);
    // do something
  }
  else if (message.GetType() == "DetectionEvent")
  {
    DetectionEvent detectionEvent;
    message.Decode(detectionEvent);
    // do something
  }
  else
  {
    LOG("receive - Unhandled type");
  }
}

Конечно, было бы лучше, если бы вы использовали std::unordered_map<Type,Handler> вместо жестко закодированной if / else if + / else цепочки, но принцип остается идентичным:

  1. Кодирование типа сообщения, отправляемого в заголовке
  2. Декодировать только заголовок при приеме и отправке на основе этого типа
  3. Декодировать сообщение protobuf в части кода, где тип статически известен
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...