NRP Core  1.4.1
engine_proto_wrapper.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 ENGINE_PROTO_WRAPPER_H
23 #define ENGINE_PROTO_WRAPPER_H
24 
25 #include <string>
26 #include <map>
27 #include <type_traits>
28 
29 #include <nlohmann/json.hpp>
30 
31 #include "nrp_protobuf/engine_grpc.pb.h"
34 #include "nrp_protobuf/config/cmake_constants.h"
38 
39 
41 
49 {
50  public:
51 
52  using mutex_t = std::timed_mutex;
53  using lock_t = std::unique_lock<EngineProtoWrapper::mutex_t>;
54 
58  EngineProtoWrapper() = delete;
59 
65  EngineProtoWrapper(const std::string &engineName,
66  const std::string &protobufPluginsPath,
67  const nlohmann::json &protobufPlugins)
68  : _loggerCfg(engineName), _engineName(engineName)
69  {
70  NRPLogger::info("EngineProtoWrapper {} has been created", engineName);
71 
72  ProtoOpsManager::getInstance().addPluginPath(protobufPluginsPath);
73  for (const auto &packageName: protobufPlugins) {
74  auto packageNameStr = packageName.template get<std::string>();
75  _protoOpsStr += packageNameStr + ",";
76  std::stringstream pluginLibName;
77  pluginLibName << "lib" << NRP_PROTO_OPS_LIB_PREFIX << packageNameStr <<
78  NRP_PROTO_OPS_LIB_SUFIX << ".so";
79  auto pluginLib = ProtoOpsManager::getInstance().loadProtobufPlugin(pluginLibName.str());
80  if(pluginLib)
81  _protoOps.template emplace_back(std::move(pluginLib));
82  else
83  throw NRPException::logCreate("Failed to load ProtobufPackage \""+packageNameStr+"\"");
84  }
85 
86  if(!_protoOpsStr.empty())
87  _protoOpsStr.pop_back();
88  }
89 
93  virtual ~EngineProtoWrapper() = default;
94 
102  void registerDataPack(const std::string & datapackName, ProtoDataPackController *interface)
103  {
104  this->_datapacksControllers.emplace(datapackName, interface);
105  }
106 
107  // TODO used only in tests, try to remove it?
109  {
110  return this->_datapacksControllers.size();
111  }
112 
116  std::vector<std::string> getNamesRegisteredDataPacks()
117  {
118  std::vector<std::string> dpNames;
119  for(auto const& dpCons : this->_datapacksControllers)
120  dpNames.push_back(dpCons.first);
121  return dpNames;
122  }
123 
127  const std::string &getEngineName() { return _engineName; }
128 
129 
133  virtual bool initRunFlag() const = 0;
134 
138  virtual bool shutdownFlag() const = 0;
139 
146  virtual void initialize(const nlohmann::json &data) = 0;
147 
151  virtual void reset() = 0;
152 
156  virtual void shutdown() = 0;
157 
165  virtual SimulationTime runLoopStep(const SimulationTime timeStep) = 0;
166 
167  void setDataPacks(const EngineGrpc::SetDataPacksRequest & data)
168  {
169  const auto numDataPacks = data.datapacks_size();
170 
171  for(int i = 0; i < numDataPacks; i++)
172  setDataPack(data.datapacks(i));
173  }
174 
175  void setDataPack(const EngineGrpc::DataPackMessage & dataPack)
176  {
177  const auto &name = dataPack.datapackid().datapackname();
178  const auto &devInterface = this->_datapacksControllers.find(name);
179 
180  if(devInterface != _datapacksControllers.end()) {
182  devInterface->second->handleDataPackData(dataPack);
183  else {
184  auto protoMsg = unpackFromAny(dataPack.data());
185  if(protoMsg)
186  devInterface->second->handleDataPackData(*protoMsg);
187  else
188  throw NRPException::logCreate("In Engine \"" + this->getEngineName() + "\", unable to deserialize datapack \"" +
189  dataPack.datapackid().datapackname() + "\" using any of the NRP-Core Protobuf plugins" +
190  "specified in the engine configuration: [" + _protoOpsStr + "]. Ensure that the parameter " +
191  "\"ProtobufPackages\" is properly set in the Engine configuration");
192  }
193  }
194  else
195  {
196  const auto errorMessage = "DataPack " + name + " is not registered in engine " + this->_engineName;
197  throw std::invalid_argument(errorMessage);
198  }
199  }
200 
201  std::unique_ptr<gpb::Message> unpackFromAny(const gpb::Any& data)
202  {
203  for(auto& mod : _protoOps) {
204  auto protoMsg = mod->unpackProtoAny(data);
205  if(protoMsg)
206  return protoMsg;
207  }
208 
209  return std::unique_ptr<gpb::Message>();
210  }
211 
212  virtual void getDataPacks(const EngineGrpc::GetDataPacksRequest & request, EngineGrpc::GetDataPacksReply * reply)
213  {
214  const auto numDataPacks = request.datapackids_size();
215 
216  for(int i = 0; i < numDataPacks; i++)
217  {
218  auto * protoDataPack = reply->add_datapacks();
219  getDataPack(request.datapackids(i).datapackname(), protoDataPack);
220  }
221  }
222 
223  bool getDataPack(const std::string& name, EngineGrpc::DataPackMessage* dpMsg)
224  {
225  dpMsg->mutable_datapackid()->set_datapackname(name);
226  dpMsg->mutable_datapackid()->set_enginename(this->_engineName);
227 
228  // ask controller to fetch datapack data. nullptr means there is no new data available
229  const auto &devInterface = this->_datapacksControllers.find(name);
230  gpb::Message* data;
231  if(devInterface != _datapacksControllers.end())
232  data = devInterface->second->getDataPackInformation();
233  else {
234  const auto errorMessage = "DataPack " + name + " is not registered in engine " + this->_engineName;
235  throw std::invalid_argument(errorMessage);
236  }
237  // set DataPackMessage data
238  if(data) {
239  setDataPackMessageData(data, dpMsg);
240  return true;
241  }
242  else
243  return false;
244  }
245 
246 
247  void setDataPackMessageData(gpb::Message* data, EngineGrpc::DataPackMessage* dpMsg)
248  {
249  bool isSet = false;
250  for (auto &mod: _protoOps) {
251  try {
252  mod->setDataPackMessageData(*data, dpMsg);
253  isSet = true;
254  }
255  catch (NRPException &) {
256  // this just means that the module couldn't process the request, try with the next one
257  }
258  }
259 
260  if (!isSet)
261  throw NRPException::logCreate("In Engine \"" + this->_engineName +
262  "\", unable to serialize datapack \"" + dpMsg->datapackid().datapackname() +
263  "\" using any of the NRP-Core Protobuf plugins specified in the"
264  " engine configuration: [" + _protoOpsStr +
265  "]. Ensure that the parameter "
266  "\"ProtobufPackages\" is properly set in the Engine configuration");
267  }
268 
269  protected:
270 
272  {
273  this->_datapacksControllers.clear();
274  }
275 
279  ProtoDataPackController* getDataPackController(const std::string & datapackName)
280  {
281  return this->_datapacksControllers.find(datapackName)->second;
282  }
283 
284 
289 
290  private:
291 
295  NRPLogger _loggerCfg;
296 
303  std::string _engineName;
304 
305 
309  std::map<std::string, ProtoDataPackController*> _datapacksControllers;
310 
311  protected:
312  std::vector<std::unique_ptr<protobuf_ops::NRPProtobufOpsIface>> _protoOps;
313  std::string _protoOpsStr = "";
314 };
315 
316 #endif // ENGINE_PROTO_WRAPPER_H
NRPException
Base NRPException class.
Definition: nrp_exceptions.h:36
EngineProtoWrapper::getDataPack
bool getDataPack(const std::string &name, EngineGrpc::DataPackMessage *dpMsg)
Definition: engine_proto_wrapper.h:223
EngineProtoWrapper::_handleDataPackMessage
bool _handleDataPackMessage
If true controllers are sent incoming DataPackMessages, if false only the contained data.
Definition: engine_proto_wrapper.h:288
EngineProtoWrapper::reset
virtual void reset()=0
Resets the simulation.
EngineProtoWrapper::getDataPacks
virtual void getDataPacks(const EngineGrpc::GetDataPacksRequest &request, EngineGrpc::GetDataPacksReply *reply)
Definition: engine_proto_wrapper.h:212
EngineProtoWrapper::setDataPackMessageData
void setDataPackMessageData(gpb::Message *data, EngineGrpc::DataPackMessage *dpMsg)
Definition: engine_proto_wrapper.h:247
EngineProtoWrapper::clearRegisteredDataPacks
void clearRegisteredDataPacks()
Definition: engine_proto_wrapper.h:271
EngineProtoWrapper::_protoOpsStr
std::string _protoOpsStr
Definition: engine_proto_wrapper.h:313
EngineProtoWrapper::EngineProtoWrapper
EngineProtoWrapper(const std::string &engineName, const std::string &protobufPluginsPath, const nlohmann::json &protobufPlugins)
Constructor.
Definition: engine_proto_wrapper.h:65
EngineProtoWrapper::getNamesRegisteredDataPacks
std::vector< std::string > getNamesRegisteredDataPacks()
Get the names of registered datapacks.
Definition: engine_proto_wrapper.h:116
proto_field_ops.h
EngineProtoWrapper::_protoOps
std::vector< std::unique_ptr< protobuf_ops::NRPProtobufOpsIface > > _protoOps
Definition: engine_proto_wrapper.h:312
EngineProtoWrapper::mutex_t
std::timed_mutex mutex_t
Definition: engine_proto_wrapper.h:52
EngineProtoWrapper::initialize
virtual void initialize(const nlohmann::json &data)=0
Initializes the simulation.
EngineProtoWrapper::lock_t
std::unique_lock< EngineProtoWrapper::mutex_t > lock_t
Definition: engine_proto_wrapper.h:53
NRPLogger::info
static void info(const FormatString &fmt, const Args &...args)
NRP logging function with message formatting for info level.
Definition: nrp_logger.h:138
EngineProtoWrapper::unpackFromAny
std::unique_ptr< gpb::Message > unpackFromAny(const gpb::Any &data)
Definition: engine_proto_wrapper.h:201
EngineProtoWrapper::shutdownFlag
virtual bool shutdownFlag() const =0
Indicates if shutdown was requested by the client.
DataPackController< google::protobuf::Message >
datapack_controller.h
EngineProtoWrapper::EngineProtoWrapper
EngineProtoWrapper()=delete
No dummy wrappers, only those with name.
EngineProtoWrapper::shutdown
virtual void shutdown()=0
Shutdowns the simulation.
EngineProtoWrapper::runLoopStep
virtual SimulationTime runLoopStep(const SimulationTime timeStep)=0
Runs a single simulation loop step.
NRPLogger
NRP Logging functions.
Definition: nrp_logger.h:45
ProtoOpsManager::loadProtobufPlugin
std::unique_ptr< protobuf_ops::NRPProtobufOpsIface > loadProtobufPlugin(const std::string &pluginLibFile)
Load a Protobuf conversion plugin from a given library.
Definition: proto_ops_manager.cpp:35
protobuf_ops.h
EngineProtoWrapper::registerDataPack
void registerDataPack(const std::string &datapackName, ProtoDataPackController *interface)
Registers a datapack controller with the given name in the engine.
Definition: engine_proto_wrapper.h:102
PluginManager::addPluginPath
void addPluginPath(const std::string &pluginPath)
Adds search path under which to look for plugins.
Definition: plugin_manager.cpp:88
EngineProtoWrapper::setDataPacks
void setDataPacks(const EngineGrpc::SetDataPacksRequest &data)
Definition: engine_proto_wrapper.h:167
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
EngineProtoWrapper::~EngineProtoWrapper
virtual ~EngineProtoWrapper()=default
Destructor.
time_utils.h
EngineProtoWrapper
Abstract class defining an interface to interact with an Engine with data exchange via protobuf messa...
Definition: engine_proto_wrapper.h:48
EngineProtoWrapper::getDataPackController
ProtoDataPackController * getDataPackController(const std::string &datapackName)
Returns the pointer to the DataPackController of the Data Pack with the specified name.
Definition: engine_proto_wrapper.h:279
EngineProtoWrapper::setDataPack
void setDataPack(const EngineGrpc::DataPackMessage &dataPack)
Definition: engine_proto_wrapper.h:175
EngineProtoWrapper::getEngineName
const std::string & getEngineName()
Get the Engine name.
Definition: engine_proto_wrapper.h:127
EngineProtoWrapper::initRunFlag
virtual bool initRunFlag() const =0
Indicates if the simulation was initialized and is running.
ProtoOpsManager::getInstance
static ProtoOpsManager & getInstance()
Get singleton instance of ProtoOpsManager.
Definition: proto_ops_manager.cpp:55
SimulationTime
std::chrono::nanoseconds SimulationTime
Definition: time_utils.h:31
EngineProtoWrapper::getNumRegisteredDataPacks
unsigned getNumRegisteredDataPacks()
Definition: engine_proto_wrapper.h:108
proto_ops_manager.h
json
nlohmann::json json
Definition: engine_json_server.cpp:31