Gazebo Transport

API Reference

13.4.1
RepHandler.hh
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Open Source Robotics Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16 */
17 
18 #ifndef GZ_TRANSPORT_REPHANDLER_HH_
19 #define GZ_TRANSPORT_REPHANDLER_HH_
20 
21 #ifdef _MSC_VER
22 #pragma warning(push)
23 #pragma warning(disable: 4251)
24 #endif
25 #include <google/protobuf/message.h>
26 #include <google/protobuf/stubs/common.h>
27 #if GOOGLE_PROTOBUF_VERSION > 2999999 && GOOGLE_PROTOBUF_VERSION < 4022000
28 #include <google/protobuf/stubs/casts.h>
29 #endif
30 #ifdef _MSC_VER
31 #pragma warning(pop)
32 #endif
33 
34 #include <functional>
35 #include <iostream>
36 #include <memory>
37 #include <string>
38 
39 #include "gz/transport/config.hh"
40 #include "gz/transport/Export.hh"
42 #include "gz/transport/Uuid.hh"
43 
44 namespace gz::transport
45 {
46  // Inline bracket to help doxygen filtering.
47  inline namespace GZ_TRANSPORT_VERSION_NAMESPACE {
48  //
51  class GZ_TRANSPORT_VISIBLE IRepHandler
52  {
54  public: IRepHandler()
55  : hUuid(Uuid().ToString())
56  {
57  }
58 
60  public: virtual ~IRepHandler() = default;
61 
66  public: virtual bool RunLocalCallback(const transport::ProtoMsg &_msgReq,
67  transport::ProtoMsg &_msgRep) = 0;
68 
75  public: virtual bool RunCallback(const std::string &_req,
76  std::string &_rep) = 0;
77 
80  public: std::string HandlerUuid() const
81  {
82  return this->hUuid;
83  }
84 
87  public: virtual std::string ReqTypeName() const = 0;
88 
91  public: virtual std::string RepTypeName() const = 0;
92 
93 #ifdef _WIN32
94 // Disable warning C4251 which is triggered by
95 // std::string
96 #pragma warning(push)
97 #pragma warning(disable: 4251)
98 #endif
100  protected: std::string hUuid;
101 #ifdef _WIN32
102 #pragma warning(pop)
103 #endif
104  };
105 
110  // the service call. 'Rep' is the protobuf message type that will be filled
112  template <typename Req, typename Rep> class RepHandler
113  : public IRepHandler
114  {
115  // Documentation inherited.
116  public: RepHandler() = default;
117 
124  public: void SetCallback(
125  const std::function<bool(const Req &, Rep &)> &_cb)
126  {
127  this->cb = _cb;
128  }
129 
130  // Documentation inherited.
131  public: bool RunLocalCallback(const transport::ProtoMsg &_msgReq,
132  transport::ProtoMsg &_msgRep)
133  {
134  // Execute the callback (if existing)
135  if (!this->cb)
136  {
137  std::cerr << "RepHandler::RunLocalCallback() error: "
138  << "Callback is NULL" << std::endl;
139  return false;
140  }
141 
142 #if GOOGLE_PROTOBUF_VERSION >= 5028000
143  const auto msgReq =
144  google::protobuf::DynamicCastMessage<Req>(&_msgReq);
145  auto msgRep =
146  google::protobuf::DynamicCastMessage<Rep>(&_msgRep);
147 #elif GOOGLE_PROTOBUF_VERSION >= 4022000
148  auto msgReq =
149  google::protobuf::internal::DownCast<const Req*>(&_msgReq);
150  auto msgRep = google::protobuf::internal::DownCast<Rep*>(&_msgRep);
151 #elif GOOGLE_PROTOBUF_VERSION > 2999999
152  auto msgReq = google::protobuf::down_cast<const Req*>(&_msgReq);
153  auto msgRep = google::protobuf::down_cast<Rep*>(&_msgRep);
154 #else
155  auto msgReq =
156  google::protobuf::internal::down_cast<const Req*>(&_msgReq);
157  auto msgRep = google::protobuf::internal::down_cast<Rep*>(&_msgRep);
158 #endif
159 
160  // Verify the dynamically casted messages are valid
161  if (msgReq == nullptr || msgRep == nullptr)
162  {
163  if (msgReq == nullptr)
164  {
165  if (_msgReq.GetDescriptor() != nullptr)
166  {
167  std::cerr << "RepHandler::RunLocalCallback() error: "
168  << "Failed to cast the request of the type "
169  << _msgReq.GetDescriptor()->full_name()
170  << " to the specified type" << '\n';
171  }
172  else
173  {
174  std::cerr << "RepHandler::RunLocalCallback() error: "
175  << "Failed to cast the request of an unknown type"
176  << " to the specified type" << '\n';
177  }
178  }
179  if (msgRep == nullptr)
180  {
181  if (_msgRep.GetDescriptor() != nullptr)
182  {
183  std::cerr << "RepHandler::RunLocalCallback() error: "
184  << "Failed to cast the response of the type "
185  << _msgRep.GetDescriptor()->full_name()
186  << " to the specified type" << '\n';
187  }
188  else
189  {
190  std::cerr << "RepHandler::RunLocalCallback() error: "
191  << "Failed to cast the response of an unknown type"
192  << " to the specified type" << '\n';
193  }
194  }
195  std::cerr.flush();
196  return false;
197  }
198 
199  return this->cb(*msgReq, *msgRep);
200  }
201 
202  // Documentation inherited.
203  public: bool RunCallback(const std::string &_req,
204  std::string &_rep)
205  {
206  // Check if we have a callback registered.
207  if (!this->cb)
208  {
209  std::cerr << "RepHandler::RunCallback() error: "
210  << "Callback is NULL" << std::endl;
211  return false;
212  }
213 
214  // Instantiate the specific protobuf message associated to this topic.
215  auto msgReq = this->CreateMsg(_req);
216  if (!msgReq)
217  {
218  return false;
219  }
220 
221  Rep msgRep;
222  if (!this->cb(*msgReq, msgRep))
223  return false;
224 
225  if (!msgRep.SerializeToString(&_rep))
226  {
227  std::cerr << "RepHandler::RunCallback(): Error serializing the "
228  << "response" << std::endl;
229  return false;
230  }
231 
232  return true;
233  }
234 
235  // Documentation inherited.
236  public: virtual std::string ReqTypeName() const
237  {
238  return std::string(Req().GetTypeName());
239  }
240 
241  // Documentation inherited.
242  public: virtual std::string RepTypeName() const
243  {
244  return std::string(Rep().GetTypeName());
245  }
246 
250  private: std::shared_ptr<Req> CreateMsg(const std::string &_data) const
251  {
252  // Instantiate a specific protobuf message
253  auto msgPtr = std::make_shared<Req>();
254 
255  // Create the message using some serialized data
256  if (!msgPtr->ParseFromString(_data))
257  {
258  std::cerr << "RepHandler::CreateMsg() error: ParseFromString failed"
259  << std::endl;
260  }
261 
262  return msgPtr;
263  }
264 
266  private: std::function<bool(const Req &, Rep &)> cb;
267  };
268  }
269 }
270 
271 #endif