Commands: support JSON in addition to binary

This commit is contained in:
Alexey Rybalchenko 2019-10-07 14:59:35 +02:00
parent caeee626a3
commit 72a8e9b33c
5 changed files with 127 additions and 51 deletions

View File

@ -15,7 +15,12 @@ add_custom_command(
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_library(${target} Commands.cxx Commands.h ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormat.h)
# JSON serialization needs to see the .fbs file at run time, save it as constexpr string instead of locating/opening it every time
file(STRINGS CommandsFormat.fbs tmp)
list(JOIN tmp "\n" commands_format_def_fbs)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CommandsFormatDef.h.in ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormatDef.h)
add_library(${target} Commands.cxx Commands.h ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormat.h ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormatDef.h)
add_library(FairMQ::${target} ALIAS ${target})
target_link_libraries(${target}

View File

@ -8,8 +8,11 @@
#include "Commands.h"
#include <fairmq/sdk/commands/CommandsFormatDef.h>
#include <fairmq/sdk/commands/CommandsFormat.h>
#include <flatbuffers/idl.h>
#include <array>
using namespace std;
@ -203,7 +206,7 @@ string GetTypeName(const Type type) { return typeNames.at(static_cast<int>(type)
FBCmd GetFBCmd(const Type type) { return typeToFBCmd.at(static_cast<int>(type)); }
string Cmds::Serialize() const
string Cmds::Serialize(const Format type) const
{
flatbuffers::FlatBufferBuilder fbb;
vector<flatbuffers::Offset<FBCommand>> commandOffsets;
@ -327,14 +330,39 @@ string Cmds::Serialize() const
auto cmds = CreateFBCommands(fbb, commands);
fbb.Finish(cmds);
if (type == Format::Binary) {
return string(reinterpret_cast<char*>(fbb.GetBufferPointer()), fbb.GetSize());
} else { // Type == Format::JSON
flatbuffers::Parser parser;
if (!parser.Parse(commandsFormatDefFbs)) {
throw CommandFormatError("Serialize couldn't parse commands format");
}
std::string json;
if (!flatbuffers::GenerateText(parser, fbb.GetBufferPointer(), &json)) {
throw CommandFormatError("Serialize couldn't serialize parsed data to JSON!");
}
return json;
}
}
void Cmds::Deserialize(const string& str)
void Cmds::Deserialize(const string& str, const Format type)
{
fCmds.clear();
auto cmds = cmd::GetFBCommands(const_cast<char*>(str.c_str()))->commands();
const flatbuffers::Vector<flatbuffers::Offset<FBCommand>>* cmds;
if (type == Format::Binary) {
cmds = cmd::GetFBCommands(const_cast<char*>(str.c_str()))->commands();
} else { // Type == Format::JSON
flatbuffers::Parser parser;
if (!parser.Parse(commandsFormatDefFbs)) {
throw CommandFormatError("Deserialize couldn't parse commands format");
}
if (!parser.Parse(str.c_str())) {
throw CommandFormatError("Deserialize couldn't parse incoming JSON string");
}
cmds = cmd::GetFBCommands(parser.builder_.GetBufferPointer())->commands();
}
for (unsigned int i = 0; i < cmds->size(); ++i) {
const fair::mq::sdk::cmd::FBCommand& cmdPtr = *(cmds->Get(i));

View File

@ -27,6 +27,11 @@ namespace sdk
namespace cmd
{
enum class Format : int {
Binary,
JSON
};
enum class Result : int {
Ok,
Failure
@ -133,7 +138,7 @@ struct CurrentState : Cmd
struct TransitionStatus : Cmd
{
explicit TransitionStatus(const std::string& id, Result result, Transition transition)
explicit TransitionStatus(const std::string& id, const Result result, const Transition transition)
: Cmd(Type::transition_status)
, fDeviceId(id)
, fResult(result)
@ -143,9 +148,9 @@ struct TransitionStatus : Cmd
std::string GetDeviceId() const { return fDeviceId; }
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
Result GetResult() const { return fResult; }
void SetResult(Result result) { fResult = result; }
void SetResult(const Result result) { fResult = result; }
Transition GetTransition() const { return fTransition; }
void SetTransition(Transition transition) { fTransition = transition; }
void SetTransition(const Transition transition) { fTransition = transition; }
private:
std::string fDeviceId;
@ -173,7 +178,7 @@ struct Config : Cmd
struct HeartbeatSubscription : Cmd
{
explicit HeartbeatSubscription(const std::string& id, Result result)
explicit HeartbeatSubscription(const std::string& id, const Result result)
: Cmd(Type::heartbeat_subscription)
, fDeviceId(id)
, fResult(result)
@ -182,7 +187,7 @@ struct HeartbeatSubscription : Cmd
std::string GetDeviceId() const { return fDeviceId; }
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
Result GetResult() const { return fResult; }
void SetResult(Result result) { fResult = result; }
void SetResult(const Result result) { fResult = result; }
private:
std::string fDeviceId;
@ -191,7 +196,7 @@ struct HeartbeatSubscription : Cmd
struct HeartbeatUnsubscription : Cmd
{
explicit HeartbeatUnsubscription(const std::string& id, Result result)
explicit HeartbeatUnsubscription(const std::string& id, const Result result)
: Cmd(Type::heartbeat_unsubscription)
, fDeviceId(id)
, fResult(result)
@ -200,7 +205,7 @@ struct HeartbeatUnsubscription : Cmd
std::string GetDeviceId() const { return fDeviceId; }
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
Result GetResult() const { return fResult; }
void SetResult(Result result) { fResult = result; }
void SetResult(const Result result) { fResult = result; }
private:
std::string fDeviceId;
@ -223,7 +228,7 @@ struct Heartbeat : Cmd
struct StateChangeSubscription : Cmd
{
explicit StateChangeSubscription(const std::string& id, Result result)
explicit StateChangeSubscription(const std::string& id, const Result result)
: Cmd(Type::state_change_subscription)
, fDeviceId(id)
, fResult(result)
@ -232,7 +237,7 @@ struct StateChangeSubscription : Cmd
std::string GetDeviceId() const { return fDeviceId; }
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
Result GetResult() const { return fResult; }
void SetResult(Result result) { fResult = result; }
void SetResult(const Result result) { fResult = result; }
private:
std::string fDeviceId;
@ -241,7 +246,7 @@ struct StateChangeSubscription : Cmd
struct StateChangeUnsubscription : Cmd
{
explicit StateChangeUnsubscription(const std::string& id, Result result)
explicit StateChangeUnsubscription(const std::string& id, const Result result)
: Cmd(Type::state_change_unsubscription)
, fDeviceId(id)
, fResult(result)
@ -250,7 +255,7 @@ struct StateChangeUnsubscription : Cmd
std::string GetDeviceId() const { return fDeviceId; }
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
Result GetResult() const { return fResult; }
void SetResult(Result result) { fResult = result; }
void SetResult(const Result result) { fResult = result; }
private:
std::string fDeviceId;
@ -259,7 +264,7 @@ struct StateChangeUnsubscription : Cmd
struct StateChange : Cmd
{
explicit StateChange(const std::string& deviceId, uint64_t taskId, State lastState, State currentState)
explicit StateChange(const std::string& deviceId, const uint64_t taskId, const State lastState, const State currentState)
: Cmd(Type::state_change)
, fDeviceId(deviceId)
, fTaskId(taskId)
@ -270,11 +275,11 @@ struct StateChange : Cmd
std::string GetDeviceId() const { return fDeviceId; }
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
uint64_t GetTaskId() const { return fTaskId; }
void SetTaskId(uint64_t taskId) { fTaskId = taskId; }
void SetTaskId(const uint64_t taskId) { fTaskId = taskId; }
fair::mq::State GetLastState() const { return fLastState; }
void SetLastState(fair::mq::State state) { fLastState = state; }
void SetLastState(const fair::mq::State state) { fLastState = state; }
fair::mq::State GetCurrentState() const { return fCurrentState; }
void SetCurrentState(fair::mq::State state) { fCurrentState = state; }
void SetCurrentState(const fair::mq::State state) { fCurrentState = state; }
private:
std::string fDeviceId;
@ -314,11 +319,11 @@ struct Cmds
Cmd& At(size_t i) { return *(fCmds.at(i)); }
size_t Size() { return fCmds.size(); }
size_t Size() const { return fCmds.size(); }
void Reset() { fCmds.clear(); }
std::string Serialize() const;
void Deserialize(const std::string&);
std::string Serialize(const Format type = Format::Binary) const;
void Deserialize(const std::string&, const Format type = Format::Binary);
private:
container fCmds;

View File

@ -0,0 +1,21 @@
/********************************************************************************
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <string>
namespace fair {
namespace mq {
namespace sdk {
namespace cmd {
constexpr auto commandsFormatDefFbs = R"(@commands_format_def_fbs@)";
} // namespace cmd
} // namespace sdk
} // namespace mq
} // namespace fair

View File

@ -77,39 +77,34 @@ TEST(Format, Construction)
ASSERT_EQ(static_cast<StateChange&>(stateChangeCmds.At(0)).GetCurrentState(), State::Ready);
}
TEST(Format, Serialization)
void fillCommands(Cmds& cmds)
{
Cmds outCmds;
cmds.Add<CheckState>();
cmds.Add<ChangeState>(Transition::Stop);
cmds.Add<DumpConfig>();
cmds.Add<SubscribeToHeartbeats>();
cmds.Add<UnsubscribeFromHeartbeats>();
cmds.Add<SubscribeToStateChange>();
cmds.Add<UnsubscribeFromStateChange>();
cmds.Add<StateChangeExitingReceived>();
cmds.Add<CurrentState>("somedeviceid", State::Running);
cmds.Add<TransitionStatus>("somedeviceid", Result::Ok, Transition::Stop);
cmds.Add<Config>("somedeviceid", "someconfig");
cmds.Add<HeartbeatSubscription>("somedeviceid", Result::Ok);
cmds.Add<HeartbeatUnsubscription>("somedeviceid", Result::Ok);
cmds.Add<Heartbeat>("somedeviceid");
cmds.Add<StateChangeSubscription>("somedeviceid", Result::Ok);
cmds.Add<StateChangeUnsubscription>("somedeviceid", Result::Ok);
cmds.Add<StateChange>("somedeviceid", 123456, State::Running, State::Ready);
}
outCmds.Add<CheckState>();
outCmds.Add<ChangeState>(Transition::Stop);
outCmds.Add<DumpConfig>();
outCmds.Add<SubscribeToHeartbeats>();
outCmds.Add<UnsubscribeFromHeartbeats>();
outCmds.Add<SubscribeToStateChange>();
outCmds.Add<UnsubscribeFromStateChange>();
outCmds.Add<StateChangeExitingReceived>();
outCmds.Add<CurrentState>("somedeviceid", State::Running);
outCmds.Add<TransitionStatus>("somedeviceid", Result::Ok, Transition::Stop);
outCmds.Add<Config>("somedeviceid", "someconfig");
outCmds.Add<HeartbeatSubscription>("somedeviceid", Result::Ok);
outCmds.Add<HeartbeatUnsubscription>("somedeviceid", Result::Ok);
outCmds.Add<Heartbeat>("somedeviceid");
outCmds.Add<StateChangeSubscription>("somedeviceid", Result::Ok);
outCmds.Add<StateChangeUnsubscription>("somedeviceid", Result::Ok);
outCmds.Add<StateChange>("somedeviceid", 123456, State::Running, State::Ready);
std::string buffer(outCmds.Serialize());
Cmds inCmds;
inCmds.Deserialize(buffer);
ASSERT_EQ(inCmds.Size(), 17);
void checkCommands(Cmds& cmds)
{
ASSERT_EQ(cmds.Size(), 17);
int count = 0;
for (const auto& cmd : inCmds) {
for (const auto& cmd : cmds) {
switch (cmd->GetType()) {
case Type::check_state:
++count;
@ -192,4 +187,26 @@ TEST(Format, Serialization)
ASSERT_EQ(count, 17);
}
TEST(Format, SerializationBinary)
{
Cmds outCmds;
fillCommands(outCmds);
std::string buffer(outCmds.Serialize());
Cmds inCmds;
inCmds.Deserialize(buffer);
checkCommands(inCmds);
}
TEST(Format, SerializationJSON)
{
Cmds outCmds;
fillCommands(outCmds);
std::string buffer(outCmds.Serialize(Format::JSON));
Cmds inCmds;
inCmds.Deserialize(buffer, Format::JSON);
checkCommands(inCmds);
}
} // namespace