NRP Core  1.4.1
protobuf_ops.h
Go to the documentation of this file.
1 /* * NRP Core - Backend infrastructure to synchronize simulations
2  *
3  * Copyright 2020-2023 NRP Team
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * This project has received funding from the European Union’s Horizon 2020
18  * Framework Programme for Research and Innovation under the Specific Grant
19  * Agreement No. 945539 (Human Brain Project SGA3).
20  */
21 
22 #ifndef PROTO_OPS_H
23 #define PROTO_OPS_H
24 
25 #include <dlfcn.h>
26 #include "google/protobuf/message.h"
27 
28 #include "nrp_protobuf/engine_grpc.pb.h"
29 #include "nrp_protobuf/nrp_server.pb.h"
32 
33 namespace gpb = google::protobuf;
34 
35 // Different conversion operations between protobuf messages and datapacks
36 namespace protobuf_ops {
37 
46  template<class MSG_TYPE, class ...REMAINING_MSG_TYPES>
47  std::unique_ptr<gpb::Message> unpackProtoAnySubset(const gpb::Any & from)
48  {
49  // If data is of MSG_TYPE type, unpack
50  if(from.Is<MSG_TYPE>())
51  {
52  MSG_TYPE * dataPack = new MSG_TYPE();
53  from.UnpackTo(dataPack);
54  return std::unique_ptr<gpb::Message>(dataPack);
55  }
56 
57  // Try with the remaining types or throw
58  if constexpr (sizeof...(REMAINING_MSG_TYPES) > 0)
59  return unpackProtoAnySubset<REMAINING_MSG_TYPES...>(from);
60  else
61  return std::unique_ptr<gpb::Message>();
62  }
63 
72  template<class MSG_TYPE, class ...REMAINING_MSG_TYPES>
73  void setDataPackMessageDataSubset(const gpb::Message & from, EngineGrpc::DataPackMessage * to)
74  {
75  // TODO datapackname and enginename are set outside of this function, should we do it here?
76  // To be considered as part of https://hbpneurorobotics.atlassian.net/browse/NRRPLT-8340
77  // Try to cast 'from' to MSG_TYPE
78  try
79  {
80  const auto& message = dynamic_cast<const MSG_TYPE &>(from);
81  to->mutable_data()->PackFrom(message);
82  return;
83  }
84  catch(const std::bad_cast& e)
85  {
86  // Do not process the exception.
87  // Bad casts aren't 'bad' in this case, they simply mean that
88  // we haven't found the right message type yet.
89  }
90 
91  // Try with the remaining types or throw
92  if constexpr (sizeof...(REMAINING_MSG_TYPES) > 0)
93  return setDataPackMessageDataSubset<REMAINING_MSG_TYPES...>(from, to);
94  else
95  {
96  const auto errorMessage = "Unable to pack data into DataPack '" +
97  to->datapackid().datapackname() +
98  "' in engine '" +
99  to->datapackid().enginename() + "'";
100 
101  throw NRPException(errorMessage);
102  }
103  }
104 
105 
115  template<class MSG_TYPE, class ...REMAINING_MSG_TYPES>
116  // TODO: use engine name from 'from' after https://hbpneurorobotics.atlassian.net/browse/NRRPLT-8340 is resolved
117  DataPackInterfaceConstSharedPtr getDataPackInterfaceFromMessageSubset(const std::string &engineName, const EngineGrpc::DataPackMessage & from)
118  {
119  const auto & dataPackId = from.datapackid();
120 
121  if(!from.has_data())
122  return DataPackInterfaceConstSharedPtr(new DataPackInterface(dataPackId.datapackname(),
123  engineName, dataPackId.datapacktype()));
124  else if(from.data().Is<MSG_TYPE>())
125  {
126  MSG_TYPE * data = new MSG_TYPE();
127  from.data().UnpackTo(data);
128 
130  new DataPack<MSG_TYPE>(dataPackId.datapackname(), engineName, data));
131  }
132 
133  if constexpr (sizeof...(REMAINING_MSG_TYPES) > 0)
134  return getDataPackInterfaceFromMessageSubset<REMAINING_MSG_TYPES...>(engineName, from);
135  else
136  return nullptr;
137  }
138 
139 
148  template<class MSG_TYPE, class ...REMAINING_MSG_TYPES>
149  void setDataPackMessageFromInterfaceSubset(const DataPackInterface & from, EngineGrpc::DataPackMessage * to)
150  {
151  // Try to cast 'from' to DataPack<MSG_TYPE>
152  try
153  {
154  const auto& message = dynamic_cast<const DataPack<MSG_TYPE> &>(from);
155  to->mutable_datapackid()->set_datapackname(message.name());
156  to->mutable_datapackid()->set_datapacktype(message.type());
157  to->mutable_datapackid()->set_enginename(message.engineName());
158  to->mutable_data()->PackFrom(message.getData());
159 
160  return;
161  }
162  catch(const std::bad_cast& e)
163  {
164  // Do not process the exception.
165  // Bad casts aren't 'bad' in this case, they simply mean that
166  // we haven't found the right message type yet.
167  }
168 
169  // Try with the remaining types or throw
170  if constexpr (sizeof...(REMAINING_MSG_TYPES) > 0)
171  return setDataPackMessageFromInterfaceSubset<REMAINING_MSG_TYPES...>(from, to);
172  else
173  throw NRPException("Failed to set DataPackMessage from DataPackInterface with name \"" + from.name() + "\"");
174  }
175 
176 
185  template<class MSG_TYPE, class ...REMAINING_MSG_TYPES>
186  void setTrajectoryMessageFromInterfaceSubset(const DataPackInterface & from, NrpCore::TrajectoryMessage * to)
187  {
188  try
189  {
190  const auto& message = dynamic_cast<const DataPack<MSG_TYPE> &>(from);
191  to->mutable_data()->PackFrom(message.getData());
192  return;
193  }
194  catch(const std::bad_cast& e)
195  {
196  // Do not process the exception.
197  // Bad casts aren't 'bad' in this case, they simply mean that
198  // we haven't found the right message type yet.
199  }
200 
201  if constexpr (sizeof...(REMAINING_MSG_TYPES) > 0)
202  return setTrajectoryMessageFromInterfaceSubset<REMAINING_MSG_TYPES...>(from, to);
203  else
204  throw NRPException::logCreate("DataPack \"" + from.name() + "\" is not supported by engine '" + from.engineName() + "'");
205  }
206 
207 
208  // Interface containing conversion operations between protobuf messages and datapacks
210  public:
211 
212  virtual std::unique_ptr<gpb::Message> unpackProtoAny(const gpb::Any &from) = 0;
213 
214  virtual void setDataPackMessageData(const gpb::Message &from, EngineGrpc::DataPackMessage *to) = 0;
215 
217  getDataPackInterfaceFromMessage(const std::string &engineName, const EngineGrpc::DataPackMessage &from) = 0;
218 
219  virtual void
220  setDataPackMessageFromInterface(const DataPackInterface &from, EngineGrpc::DataPackMessage *to) = 0;
221 
222  virtual void setTrajectoryMessageFromInterface(const DataPackInterface & from, NrpCore::TrajectoryMessage * to) = 0;
223  };
224 
225  // Template class implementing NRPProtobufOpsIface
226  template<class ...MSG_TYPES>
228  public:
229 
230  std::unique_ptr<gpb::Message> unpackProtoAny(const gpb::Any& from) override
231  { return unpackProtoAnySubset<MSG_TYPES...>(from); }
232 
233  void setDataPackMessageData(const gpb::Message &from, EngineGrpc::DataPackMessage *to) override
234  { setDataPackMessageDataSubset<MSG_TYPES...>(from, to); }
235 
236  DataPackInterfaceConstSharedPtr getDataPackInterfaceFromMessage(const std::string &engineName, const EngineGrpc::DataPackMessage &from) override
237  { return getDataPackInterfaceFromMessageSubset<MSG_TYPES...>(engineName, from); }
238 
239  void setDataPackMessageFromInterface(const DataPackInterface & from, EngineGrpc::DataPackMessage * to) override
240  { setDataPackMessageFromInterfaceSubset<MSG_TYPES...>(from, to); }
241 
242  void setTrajectoryMessageFromInterface(const DataPackInterface & from, NrpCore::TrajectoryMessage * to) override
243  {
244  setTrajectoryMessageFromInterfaceSubset<MSG_TYPES...>(from, to);
245  }
246  };
247 }
248 
249 
250 // These macros are used to compile protobuf conversion libraries which can be then dynamically loaded and used in
251 // nrp-core
252 
253 #define CREATE_PROTOBUF_OPS_FCN_STR "CreateNRPProtobufOps"
254 
258 #define CREATE_PROTOBUF_OPS(proto_ops_class) \
259  extern "C" protobuf_ops::NRPProtobufOpsIface *CreateNRPProtobufOps (); \
260  protobuf_ops::NRPProtobufOpsIface *CreateNRPProtobufOps () { \
261  return new proto_ops_class(); \
262  }
263 
264 #endif // PROTO_OPS_H
NRPException
Base NRPException class.
Definition: nrp_exceptions.h:36
DataPackInterfaceConstSharedPtr
DataPackInterface::const_shared_ptr DataPackInterfaceConstSharedPtr
Definition: datapack_interface.h:180
protobuf_ops::NRPProtobufOps::setDataPackMessageData
void setDataPackMessageData(const gpb::Message &from, EngineGrpc::DataPackMessage *to) override
Definition: protobuf_ops.h:233
protobuf_ops::NRPProtobufOpsIface::setDataPackMessageFromInterface
virtual void setDataPackMessageFromInterface(const DataPackInterface &from, EngineGrpc::DataPackMessage *to)=0
protobuf_ops::setDataPackMessageDataSubset
void setDataPackMessageDataSubset(const gpb::Message &from, EngineGrpc::DataPackMessage *to)
Set a protobuf datapack msg data field from a protobuf message.
Definition: protobuf_ops.h:73
protobuf_ops::NRPProtobufOpsIface::getDataPackInterfaceFromMessage
virtual DataPackInterfaceConstSharedPtr getDataPackInterfaceFromMessage(const std::string &engineName, const EngineGrpc::DataPackMessage &from)=0
nrp_exceptions.h
protobuf_ops::NRPProtobufOpsIface::unpackProtoAny
virtual std::unique_ptr< gpb::Message > unpackProtoAny(const gpb::Any &from)=0
protobuf_ops::NRPProtobufOpsIface::setTrajectoryMessageFromInterface
virtual void setTrajectoryMessageFromInterface(const DataPackInterface &from, NrpCore::TrajectoryMessage *to)=0
protobuf_ops::NRPProtobufOps::getDataPackInterfaceFromMessage
DataPackInterfaceConstSharedPtr getDataPackInterfaceFromMessage(const std::string &engineName, const EngineGrpc::DataPackMessage &from) override
Definition: protobuf_ops.h:236
protobuf_ops::unpackProtoAnySubset
std::unique_ptr< gpb::Message > unpackProtoAnySubset(const gpb::Any &from)
Attempts to unpack an Any protobuf msg to any of the template parameter classes.
Definition: protobuf_ops.h:47
protobuf_ops::setDataPackMessageFromInterfaceSubset
void setDataPackMessageFromInterfaceSubset(const DataPackInterface &from, EngineGrpc::DataPackMessage *to)
Sets the data field of a datapack protobuf message from a datapack interface.
Definition: protobuf_ops.h:149
protobuf_ops::NRPProtobufOps::unpackProtoAny
std::unique_ptr< gpb::Message > unpackProtoAny(const gpb::Any &from) override
Definition: protobuf_ops.h:230
protobuf_ops::getDataPackInterfaceFromMessageSubset
DataPackInterfaceConstSharedPtr getDataPackInterfaceFromMessageSubset(const std::string &engineName, const EngineGrpc::DataPackMessage &from)
Finds the type of protobuf msg contained in 'from' data field and creates a datapack from it.
Definition: protobuf_ops.h:117
protobuf_ops::NRPProtobufOps
Definition: protobuf_ops.h:227
protobuf_ops::NRPProtobufOps::setTrajectoryMessageFromInterface
void setTrajectoryMessageFromInterface(const DataPackInterface &from, NrpCore::TrajectoryMessage *to) override
Definition: protobuf_ops.h:242
protobuf_ops::setTrajectoryMessageFromInterfaceSubset
void setTrajectoryMessageFromInterfaceSubset(const DataPackInterface &from, NrpCore::TrajectoryMessage *to)
Sets the data field of a datapack protobuf message from a datapack interface.
Definition: protobuf_ops.h:186
NRPException::logCreate
static EXCEPTION logCreate(LOG_EXCEPTION_T &exception, const std::string &msg, NRPLogger::spdlog_out_fcn_t spdlogCall=NRPLogger::critical)
Definition: nrp_exceptions.h:73
datapack.h
protobuf_ops::NRPProtobufOpsIface::setDataPackMessageData
virtual void setDataPackMessageData(const gpb::Message &from, EngineGrpc::DataPackMessage *to)=0
DataPack
Base datapack class.
Definition: datapack.h:36
protobuf_ops
Definition: protobuf_ops.h:36
protobuf_ops::NRPProtobufOpsIface
Definition: protobuf_ops.h:209
DataPackInterface
Interface to datapacks.
Definition: datapack_interface.h:89
protobuf_ops::NRPProtobufOps::setDataPackMessageFromInterface
void setDataPackMessageFromInterface(const DataPackInterface &from, EngineGrpc::DataPackMessage *to) override
Definition: protobuf_ops.h:239
DataPackInterface::name
const std::string & name() const
Definition: datapack_interface.cpp:34
DataPackInterface::engineName
const std::string & engineName() const
Definition: datapack_interface.cpp:54