/******************************************************************************** * 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 "Commands.h" #include #include #include #include using namespace std; namespace fair { namespace mq { namespace sdk { namespace cmd { array fbResultToResult = { { Result::Ok, Result::Failure } }; array resultToFBResult = { { FBResult::FBResult_Ok, FBResult::FBResult_Failure } }; array resultNames = { { "Ok", "Failure" } }; array typeNames = { { "CheckState", "ChangeState", "DumpConfig", "SubscribeToStateChange", "UnsubscribeFromStateChange", "StateChangeExitingReceived", "GetProperties", "SetProperties", "SubscriptionHeartbeat", "CurrentState", "TransitionStatus", "Config", "StateChangeSubscription", "StateChangeUnsubscription", "StateChange", "Properties", "PropertiesSet" } }; array fbStateToMQState = { { fair::mq::State::Undefined, fair::mq::State::Ok, fair::mq::State::Error, fair::mq::State::Idle, fair::mq::State::InitializingDevice, fair::mq::State::Initialized, fair::mq::State::Binding, fair::mq::State::Bound, fair::mq::State::Connecting, fair::mq::State::DeviceReady, fair::mq::State::InitializingTask, fair::mq::State::Ready, fair::mq::State::Running, fair::mq::State::ResettingTask, fair::mq::State::ResettingDevice, fair::mq::State::Exiting } }; array mqStateToFBState = { { sdk::cmd::FBState_Undefined, sdk::cmd::FBState_Ok, sdk::cmd::FBState_Error, sdk::cmd::FBState_Idle, sdk::cmd::FBState_InitializingDevice, sdk::cmd::FBState_Initialized, sdk::cmd::FBState_Binding, sdk::cmd::FBState_Bound, sdk::cmd::FBState_Connecting, sdk::cmd::FBState_DeviceReady, sdk::cmd::FBState_InitializingTask, sdk::cmd::FBState_Ready, sdk::cmd::FBState_Running, sdk::cmd::FBState_ResettingTask, sdk::cmd::FBState_ResettingDevice, sdk::cmd::FBState_Exiting } }; array fbTransitionToMQTransition = { { fair::mq::Transition::Auto, fair::mq::Transition::InitDevice, fair::mq::Transition::CompleteInit, fair::mq::Transition::Bind, fair::mq::Transition::Connect, fair::mq::Transition::InitTask, fair::mq::Transition::Run, fair::mq::Transition::Stop, fair::mq::Transition::ResetTask, fair::mq::Transition::ResetDevice, fair::mq::Transition::End, fair::mq::Transition::ErrorFound } }; array mqTransitionToFBTransition = { { sdk::cmd::FBTransition_Auto, sdk::cmd::FBTransition_InitDevice, sdk::cmd::FBTransition_CompleteInit, sdk::cmd::FBTransition_Bind, sdk::cmd::FBTransition_Connect, sdk::cmd::FBTransition_InitTask, sdk::cmd::FBTransition_Run, sdk::cmd::FBTransition_Stop, sdk::cmd::FBTransition_ResetTask, sdk::cmd::FBTransition_ResetDevice, sdk::cmd::FBTransition_End, sdk::cmd::FBTransition_ErrorFound } }; array typeToFBCmd = { { FBCmd::FBCmd_check_state, FBCmd::FBCmd_change_state, FBCmd::FBCmd_dump_config, FBCmd::FBCmd_subscribe_to_state_change, FBCmd::FBCmd_unsubscribe_from_state_change, FBCmd::FBCmd_state_change_exiting_received, FBCmd::FBCmd_get_properties, FBCmd::FBCmd_set_properties, FBCmd::FBCmd_subscription_heartbeat, FBCmd::FBCmd_current_state, FBCmd::FBCmd_transition_status, FBCmd::FBCmd_config, FBCmd::FBCmd_state_change_subscription, FBCmd::FBCmd_state_change_unsubscription, FBCmd::FBCmd_state_change, FBCmd::FBCmd_properties, FBCmd::FBCmd_properties_set } }; array fbCmdToType = { { Type::check_state, Type::change_state, Type::dump_config, Type::subscribe_to_state_change, Type::unsubscribe_from_state_change, Type::state_change_exiting_received, Type::get_properties, Type::set_properties, Type::subscription_heartbeat, Type::current_state, Type::transition_status, Type::config, Type::state_change_subscription, Type::state_change_unsubscription, Type::state_change, Type::properties, Type::properties_set } }; fair::mq::State GetMQState(const FBState state) { return fbStateToMQState.at(state); } FBState GetFBState(const fair::mq::State state) { return mqStateToFBState.at(static_cast(state)); } fair::mq::Transition GetMQTransition(const FBTransition transition) { return fbTransitionToMQTransition.at(transition); } FBTransition GetFBTransition(const fair::mq::Transition transition) { return mqTransitionToFBTransition.at(static_cast(transition)); } Result GetResult(const FBResult result) { return fbResultToResult.at(result); } FBResult GetFBResult(const Result result) { return resultToFBResult.at(static_cast(result)); } string GetResultName(const Result result) { return resultNames.at(static_cast(result)); } string GetTypeName(const Type type) { return typeNames.at(static_cast(type)); } FBCmd GetFBCmd(const Type type) { return typeToFBCmd.at(static_cast(type)); } string Cmds::Serialize(const Format type) const { flatbuffers::FlatBufferBuilder fbb; vector> commandOffsets; for (auto& cmd : fCmds) { flatbuffers::Offset cmdOffset; unique_ptr cmdBuilder; // delay the creation of the builder, because child strings need to be constructed first (which are conditional) switch (cmd->GetType()) { case Type::check_state: { cmdBuilder = tools::make_unique(fbb); } break; case Type::change_state: { cmdBuilder = tools::make_unique(fbb); cmdBuilder->add_transition(GetFBTransition(static_cast(*cmd).GetTransition())); } break; case Type::dump_config: { cmdBuilder = tools::make_unique(fbb); } break; break; case Type::subscribe_to_state_change: { auto _cmd = static_cast(*cmd); cmdBuilder = tools::make_unique(fbb); cmdBuilder->add_interval(_cmd.GetInterval()); } break; case Type::unsubscribe_from_state_change: { cmdBuilder = tools::make_unique(fbb); } break; case Type::state_change_exiting_received: { cmdBuilder = tools::make_unique(fbb); } break; case Type::get_properties: { auto _cmd = static_cast(*cmd); auto query = fbb.CreateString(_cmd.GetQuery()); cmdBuilder = tools::make_unique(fbb); cmdBuilder->add_request_id(_cmd.GetRequestId()); cmdBuilder->add_property_query(query); } break; case Type::set_properties: { auto _cmd = static_cast(*cmd); std::vector> propsVector; for (auto const& e : _cmd.GetProps()) { auto const key(fbb.CreateString(e.first)); auto const val(fbb.CreateString(e.second)); propsVector.push_back(CreateFBProperty(fbb, key, val)); } auto props = fbb.CreateVector(propsVector); cmdBuilder = tools::make_unique(fbb); cmdBuilder->add_request_id(_cmd.GetRequestId()); cmdBuilder->add_properties(props); } break; case Type::subscription_heartbeat: { auto _cmd = static_cast(*cmd); cmdBuilder = tools::make_unique(fbb); cmdBuilder->add_interval(_cmd.GetInterval()); } break; case Type::current_state: { auto _cmd = static_cast(*cmd); auto deviceId = fbb.CreateString(_cmd.GetDeviceId()); cmdBuilder = tools::make_unique(fbb); cmdBuilder->add_device_id(deviceId); cmdBuilder->add_current_state(GetFBState(_cmd.GetCurrentState())); } break; case Type::transition_status: { auto _cmd = static_cast(*cmd); auto deviceId = fbb.CreateString(_cmd.GetDeviceId()); cmdBuilder = tools::make_unique(fbb); cmdBuilder->add_device_id(deviceId); cmdBuilder->add_task_id(_cmd.GetTaskId()); cmdBuilder->add_result(GetFBResult(_cmd.GetResult())); cmdBuilder->add_transition(GetFBTransition(_cmd.GetTransition())); cmdBuilder->add_current_state(GetFBState(_cmd.GetCurrentState())); } break; case Type::config: { auto _cmd = static_cast(*cmd); auto deviceId = fbb.CreateString(_cmd.GetDeviceId()); auto config = fbb.CreateString(_cmd.GetConfig()); cmdBuilder = tools::make_unique(fbb); cmdBuilder->add_device_id(deviceId); cmdBuilder->add_config_string(config); } break; case Type::state_change_subscription: { auto _cmd = static_cast(*cmd); auto deviceId = fbb.CreateString(_cmd.GetDeviceId()); cmdBuilder = tools::make_unique(fbb); cmdBuilder->add_device_id(deviceId); cmdBuilder->add_task_id(_cmd.GetTaskId()); cmdBuilder->add_result(GetFBResult(_cmd.GetResult())); } break; case Type::state_change_unsubscription: { auto _cmd = static_cast(*cmd); auto deviceId = fbb.CreateString(_cmd.GetDeviceId()); cmdBuilder = tools::make_unique(fbb); cmdBuilder->add_device_id(deviceId); cmdBuilder->add_task_id(_cmd.GetTaskId()); cmdBuilder->add_result(GetFBResult(_cmd.GetResult())); } break; case Type::state_change: { auto _cmd = static_cast(*cmd); auto deviceId = fbb.CreateString(_cmd.GetDeviceId()); cmdBuilder = tools::make_unique(fbb); cmdBuilder->add_device_id(deviceId); cmdBuilder->add_task_id(_cmd.GetTaskId()); cmdBuilder->add_last_state(GetFBState(_cmd.GetLastState())); cmdBuilder->add_current_state(GetFBState(_cmd.GetCurrentState())); } break; case Type::properties: { auto _cmd = static_cast(*cmd); auto deviceId = fbb.CreateString(_cmd.GetDeviceId()); std::vector> propsVector; for (const auto& e : _cmd.GetProps()) { auto key = fbb.CreateString(e.first); auto val = fbb.CreateString(e.second); auto prop = CreateFBProperty(fbb, key, val); propsVector.push_back(prop); } auto props = fbb.CreateVector(propsVector); cmdBuilder = tools::make_unique(fbb); cmdBuilder->add_device_id(deviceId); cmdBuilder->add_request_id(_cmd.GetRequestId()); cmdBuilder->add_result(GetFBResult(_cmd.GetResult())); cmdBuilder->add_properties(props); } break; case Type::properties_set: { auto _cmd = static_cast(*cmd); auto deviceId = fbb.CreateString(_cmd.GetDeviceId()); cmdBuilder = tools::make_unique(fbb); cmdBuilder->add_device_id(deviceId); cmdBuilder->add_request_id(_cmd.GetRequestId()); cmdBuilder->add_result(GetFBResult(_cmd.GetResult())); } break; default: throw CommandFormatError("unrecognized command type given to fair::mq::cmd::Cmds::Serialize()"); break; } cmdBuilder->add_command_id(typeToFBCmd.at(static_cast(cmd->GetType()))); cmdOffset = cmdBuilder->Finish(); commandOffsets.push_back(cmdOffset); } auto commands = fbb.CreateVector(commandOffsets); auto cmds = CreateFBCommands(fbb, commands); fbb.Finish(cmds); if (type == Format::Binary) { return string(reinterpret_cast(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, const Format type) { fCmds.clear(); const flatbuffers::Vector>* cmds; if (type == Format::Binary) { cmds = cmd::GetFBCommands(const_cast(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)); switch (cmdPtr.command_id()) { case FBCmd_check_state: fCmds.emplace_back(make()); break; case FBCmd_change_state: fCmds.emplace_back(make(GetMQTransition(cmdPtr.transition()))); break; case FBCmd_dump_config: fCmds.emplace_back(make()); break; case FBCmd_subscribe_to_state_change: fCmds.emplace_back(make(cmdPtr.interval())); break; case FBCmd_unsubscribe_from_state_change: fCmds.emplace_back(make()); break; case FBCmd_state_change_exiting_received: fCmds.emplace_back(make()); break; case FBCmd_get_properties: fCmds.emplace_back(make(cmdPtr.request_id(), cmdPtr.property_query()->str())); break; case FBCmd_set_properties: { std::vector> properties; auto props = cmdPtr.properties(); for (unsigned int j = 0; j < props->size(); ++j) { properties.emplace_back(props->Get(j)->key()->str(), props->Get(j)->value()->str()); } fCmds.emplace_back(make(cmdPtr.request_id(), properties)); } break; case FBCmd_subscription_heartbeat: fCmds.emplace_back(make(cmdPtr.interval())); break; case FBCmd_current_state: fCmds.emplace_back(make(cmdPtr.device_id()->str(), GetMQState(cmdPtr.current_state()))); break; case FBCmd_transition_status: fCmds.emplace_back(make(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetResult(cmdPtr.result()), GetMQTransition(cmdPtr.transition()), GetMQState(cmdPtr.current_state()))); break; case FBCmd_config: fCmds.emplace_back(make(cmdPtr.device_id()->str(), cmdPtr.config_string()->str())); break; case FBCmd_state_change_subscription: fCmds.emplace_back(make(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetResult(cmdPtr.result()))); break; case FBCmd_state_change_unsubscription: fCmds.emplace_back(make(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetResult(cmdPtr.result()))); break; case FBCmd_state_change: fCmds.emplace_back(make(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetMQState(cmdPtr.last_state()), GetMQState(cmdPtr.current_state()))); break; case FBCmd_properties: { std::vector> properties; auto props = cmdPtr.properties(); for (unsigned int j = 0; j < props->size(); ++j) { properties.emplace_back(props->Get(j)->key()->str(), props->Get(j)->value()->str()); } fCmds.emplace_back(make(cmdPtr.device_id()->str(), cmdPtr.request_id(), GetResult(cmdPtr.result()), properties)); } break; case FBCmd_properties_set: fCmds.emplace_back(make(cmdPtr.device_id()->str(), cmdPtr.request_id(), GetResult(cmdPtr.result()))); break; default: throw CommandFormatError("unrecognized command type given to fair::mq::cmd::Cmds::Deserialize()"); break; } } } } // namespace cmd } // namespace sdk } // namespace mq } // namespace fair