Gazebo Transport

API Reference

13.4.0
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
45 {
46  namespace transport
47  {
48  // Inline bracket to help doxygen filtering.
49  inline namespace GZ_TRANSPORT_VERSION_NAMESPACE {
50  //
53  class GZ_TRANSPORT_VISIBLE IRepHandler
54  {
56  public: IRepHandler()
57  : hUuid(Uuid().ToString())
58  {
59  }
60 
62  public: virtual ~IRepHandler() = default;
63 
68  public: virtual bool RunLocalCallback(const transport::ProtoMsg &_msgReq,
69  transport::ProtoMsg &_msgRep) = 0;
70 
77  public: virtual bool RunCallback(const std::string &_req,
78  std::string &_rep) = 0;
79 
82  public: std::string HandlerUuid() const
83  {
84  return this->hUuid;
85  }
86 
89  public: virtual std::string ReqTypeName() const = 0;
90 
93  public: virtual std::string RepTypeName() const = 0;
94 
95 #ifdef _WIN32
96 // Disable warning C4251 which is triggered by
97 // std::string
98 #pragma warning(push)
99 #pragma warning(disable: 4251)
100 #endif
102  protected: std::string hUuid;
103 #ifdef _WIN32
104 #pragma warning(pop)
105 #endif
106  };
107 
112  // the service call. 'Rep' is the protobuf message type that will be filled
114  template <typename Req, typename Rep> class RepHandler
115  : public IRepHandler
116  {
117  // Documentation inherited.
118  public: RepHandler() = default;
119 
126  public: void SetCallback(
127  const std::function<bool(const Req &, Rep &)> &_cb)
128  {
129  this->cb = _cb;
130  }
131 
132  // Documentation inherited.
133  public: bool RunLocalCallback(const transport::ProtoMsg &_msgReq,
134  transport::ProtoMsg &_msgRep)
135  {
136  // Execute the callback (if existing)
137  if (!this->cb)
138  {
139  std::cerr << "RepHandler::RunLocalCallback() error: "
140  << "Callback is NULL" << std::endl;
141  return false;
142  }
143 
144 #if GOOGLE_PROTOBUF_VERSION >= 5028000
145  const auto msgReq =
146  google::protobuf::DynamicCastMessage<Req>(&_msgReq);
147  auto msgRep =
148  google::protobuf::DynamicCastMessage<Rep>(&_msgRep);
149 #elif GOOGLE_PROTOBUF_VERSION >= 4022000
150  auto msgReq =
151  google::protobuf::internal::DownCast<const Req*>(&_msgReq);
152  auto msgRep = google::protobuf::internal::DownCast<Rep*>(&_msgRep);
153 #elif GOOGLE_PROTOBUF_VERSION > 2999999
154  auto msgReq = google::protobuf::down_cast<const Req*>(&_msgReq);
155  auto msgRep = google::protobuf::down_cast<Rep*>(&_msgRep);
156 #else
157  auto msgReq =
158  google::protobuf::internal::down_cast<const Req*>(&_msgReq);
159  auto msgRep = google::protobuf::internal::down_cast<Rep*>(&_msgRep);
160 #endif
161 
162  // Verify the dynamically casted messages are valid
163  if (msgReq == nullptr || msgRep == nullptr)
164  {
165  if (msgReq == nullptr)
166  {
167  if (_msgReq.GetDescriptor() != nullptr)
168  {
169  std::cerr << "RepHandler::RunLocalCallback() error: "
170  << "Failed to cast the request of the type "
171  << _msgReq.GetDescriptor()->full_name()
172  << " to the specified type" << '\n';
173  }
174  else
175  {
176  std::cerr << "RepHandler::RunLocalCallback() error: "
177  << "Failed to cast the request of an unknown type"
178  << " to the specified type" << '\n';
179  }
180  }
181  if (msgRep == nullptr)
182  {
183  if (_msgRep.GetDescriptor() != nullptr)
184  {
185  std::cerr << "RepHandler::RunLocalCallback() error: "
186  << "Failed to cast the response of the type "
187  << _msgRep.GetDescriptor()->full_name()
188  << " to the specified type" << '\n';
189  }
190  else
191  {
192  std::cerr << "RepHandler::RunLocalCallback() error: "
193  << "Failed to cast the response of an unknown type"
194  << " to the specified type" << '\n';
195  }
196  }
197  std::cerr.flush();
198  return false;
199  }
200 
201  return this->cb(*msgReq, *msgRep);
202  }
203 
204  // Documentation inherited.
205  public: bool RunCallback(const std::string &_req,
206  std::string &_rep)
207  {
208  // Check if we have a callback registered.
209  if (!this->cb)
210  {
211  std::cerr << "RepHandler::RunCallback() error: "
212  << "Callback is NULL" << std::endl;
213  return false;
214  }
215 
216  // Instantiate the specific protobuf message associated to this topic.
217  auto msgReq = this->CreateMsg(_req);
218  if (!msgReq)
219  {
220  return false;
221  }
222 
223  Rep msgRep;
224  if (!this->cb(*msgReq, msgRep))
225  return false;
226 
227  if (!msgRep.SerializeToString(&_rep))
228  {
229  std::cerr << "RepHandler::RunCallback(): Error serializing the "
230  << "response" << std::endl;
231  return false;
232  }
233 
234  return true;
235  }
236 
237  // Documentation inherited.
238  public: virtual std::string ReqTypeName() const
239  {
240  return Req().GetTypeName();
241  }
242 
243  // Documentation inherited.
244  public: virtual std::string RepTypeName() const
245  {
246  return Rep().GetTypeName();
247  }
248 
252  private: std::shared_ptr<Req> CreateMsg(const std::string &_data) const
253  {
254  // Instantiate a specific protobuf message
255  std::shared_ptr<Req> msgPtr(new Req());
256 
257  // Create the message using some serialized data
258  if (!msgPtr->ParseFromString(_data))
259  {
260  std::cerr << "RepHandler::CreateMsg() error: ParseFromString failed"
261  << std::endl;
262  }
263 
264  return msgPtr;
265  }
266 
268  private: std::function<bool(const Req &, Rep &)> cb;
269  };
270  }
271  }
272 }
273 
274 #endif