Index: CloudConnect/CloudConnectController.cpp =================================================================== diff -u -re9aa2c82ccb8cb5662f05ed878d2f7b5ef9f4a65 -rfe8875710ffd0f7ecc8df54bb5dee1be3d28212b --- CloudConnect/CloudConnectController.cpp (.../CloudConnectController.cpp) (revision e9aa2c82ccb8cb5662f05ed878d2f7b5ef9f4a65) +++ CloudConnect/CloudConnectController.cpp (.../CloudConnectController.cpp) (revision fe8875710ffd0f7ecc8df54bb5dee1be3d28212b) @@ -24,16 +24,25 @@ #include #include +// BEGIN: Mesg Stats #include #include #include +// END: Mesg Stats +// BEGIN: Protobuf capture +#include +#include +#include +// END: Protobuf capture + #include "CloudConnectController.h" #include "LeahiMsgDefs.pb.h" #include "LeahiMsgProtoUtils.h" Q_LOGGING_CATEGORY(logConfig, "config") Q_LOGGING_CATEGORY(logProto, "proto") +Q_LOGGING_CATEGORY(logProtoCapture, "proto.capture") // TODO: Protobuf capture Q_LOGGING_CATEGORY(logCanRouting, "can.routing") Q_LOGGING_CATEGORY(logMqtt, "mqtt") Q_LOGGING_CATEGORY(logMqttStats, "mqtt.stats") @@ -114,6 +123,13 @@ return false; } + // BEGIN: Protobuf capture + config.beginGroup(QStringLiteral("Capture")); + _captureSerFile = new QFile(config.value("SerFile").toString(), this); + _captureJsonFile = new QFile(config.value("JsonFile").toString(), this); + config.endGroup(); + // END: Protobuf capture + return true; } @@ -333,6 +349,9 @@ QByteArray payload; if (leahi::canMessageToProtobufByteArray(QDateTime::currentDateTime(), msg, payload)) { + // TODO: Protobuf capture + // captureProtobuf(payload); + qint32 pubId; if (_mqttClient.publish(mqttTopic(it->topic), payload, pubId)) { qCWarning(logMqtt).noquote() << QString("message[ msgId=0x%1 (%2), seq=%3 ], published (pubId=%4)") @@ -532,6 +551,76 @@ qCDebug(logProto).noquote() << QString::fromStdString(typeName) << ":" << Qt::endl << QString::fromStdString(json); } +// BEGIN: Protobuf capture +void CloudConnectController::captureProtobuf(const QByteArray &payload) +{ + static auto encodeVarint = [](quint32 value) -> QByteArray { + QByteArray out; + do { + quint8 byte = value & 0x7F; + value >>= 7; + if (value != 0) { + byte |= 0x80; // more bytes follow + } + out.append(static_cast(byte)); + } while (value != 0); + return out; + }; + + if (_captureSerFile) { + if (_captureSerFile->open(QIODevice::WriteOnly | QIODevice::Append)) { + qCInfo(logProtoCapture).noquote() << QString("wrote to protobuf capture file %1 (sizes: length=%2, payload=%3)") + .arg(_captureSerFile->fileName()) + .arg(_captureSerFile->write(encodeVarint(static_cast(payload.size())))) + .arg(_captureSerFile->write(payload)); + _captureSerFile->flush(); + _captureSerFile->close(); + } + else { + qCCritical(logProtoCapture).noquote() << QString("cannot open capture ser file %1").arg(_captureSerFile->fileName()); + } + } + else { + qCCritical(logProtoCapture).noquote() << QString("capture ser file is null"); + } + + if (_captureJsonFile) { + if (_captureJsonFile->open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { + leahi::messages::Envelope envelope; + if (envelope.ParseFromArray(payload.constData(), payload.size())) { + const leahi::messages::Header &header = envelope.header(); + const google::protobuf::Descriptor *desc = + google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName( + leahi::msgIdToProtoName(static_cast(header.msgid()))); + if (desc) { + google::protobuf::DynamicMessageFactory factory; + std::unique_ptr body(factory.GetPrototype(desc)->New()); + if (body->ParseFromArray(payload.constData(), payload.size())) { + std::string json; + google::protobuf::util::JsonPrintOptions opts; + opts.add_whitespace = true; + opts.always_print_primitive_fields = true; + google::protobuf::util::MessageToJsonString(*body, &json, opts); + QString jsonStr = QString::fromStdString(json); + qCInfo(logProtoCapture).noquote() << QString("wrote to capture json file %1 (size: json=%2)") + .arg(_captureJsonFile->fileName()) + .arg(_captureJsonFile->write(jsonStr.toLatin1())); + _captureJsonFile->flush(); + _captureJsonFile->close(); + } + } + } + } + else { + qCCritical(logProtoCapture).noquote() << QString("cannot open capture json file %1").arg(_captureJsonFile->fileName()); + } + } + else { + qCCritical(logProtoCapture).noquote() << QString("capture json file is null"); + } +} +// END: Protobuf capture + // BEGIN: Mesg Stats QString CloudConnectController::canStats(Can::MsgId msgId, qint64 sinceLastUs) const {