Gazebo Transport

API Reference

15.1.0
SubscriptionHandler.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_SUBSCRIPTIONHANDLER_HH_
19#define GZ_TRANSPORT_SUBSCRIPTIONHANDLER_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 >= 3000000 && 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 <chrono>
35#include <cstddef>
36#include <functional>
37#include <iostream>
38#include <memory>
39#include <string>
40#include <utility>
41
42#include <gz/msgs/Factory.hh>
43
44#include "gz/transport/config.hh"
45#include "gz/transport/Export.hh"
50#include "gz/transport/Uuid.hh"
51
52namespace zenoh
53{
54 // Forward declaration.
55 class Session;
56}
57
58namespace gz::transport
59{
60 // Inline bracket to help doxygen filtering.
61 inline namespace GZ_TRANSPORT_VERSION_NAMESPACE {
62 //
64 class SubscriptionHandlerBasePrivate;
65
68 class GZ_TRANSPORT_VISIBLE SubscriptionHandlerBase
69 {
74 public: explicit SubscriptionHandlerBase(
75 const std::string &_pUuid,
76 const std::string &_nUuid,
77 const SubscribeOptions &_opts = SubscribeOptions());
78
80 public: virtual ~SubscriptionHandlerBase();
81
85 public: virtual std::string TypeName() = 0;
86
89 public: std::string ProcUuid() const;
90
93 public: std::string NodeUuid() const;
94
97 public: std::string HandlerUuid() const;
98
101 public: bool IgnoreLocalMessages() const;
102
106 protected: bool UpdateThrottling();
107
110
113 protected: double periodNs;
114
115#ifdef _WIN32
116// Disable warning C4251 which is triggered by
117// std::*
118#pragma warning(push)
119#pragma warning(disable: 4251)
120#endif
123#ifdef _WIN32
124#pragma warning(pop)
125#endif
126 };
127
136 class GZ_TRANSPORT_VISIBLE ISubscriptionHandler
138 {
143 public: explicit ISubscriptionHandler(
144 const std::string &_pUuid,
145 const std::string &_nUuid,
146 const SubscribeOptions &_opts = SubscribeOptions());
147
149 public: virtual ~ISubscriptionHandler() = default;
150
155 public: virtual bool RunLocalCallback(
156 const ProtoMsg &_msg,
157 const MessageInfo &_info) = 0;
158
164 const std::string &_data,
165 const std::string &_type) const = 0;
166
170 const char *_data,
171 std::size_t _size,
172 const std::string &_type)>;
173
187 const char *_data,
188 std::size_t _size,
189 const std::string &_type) const;
190
196 protected: void SetMsgFactory(MsgFactory _factory);
197
198#ifdef HAVE_ZENOH
203 public: void CreateLivelinessToken(
205 const FullyQualifiedTopic &_fullyQualifiedTopic);
206
211 public: void CreateGenericZenohSubscriber(
213 const FullyQualifiedTopic &_fullyQualifiedTopic);
214#endif
215 };
216
221 template <typename T> class SubscriptionHandler
222 : public ISubscriptionHandler
223 {
224 // Documentation inherited.
225 public: explicit SubscriptionHandler(const std::string &_pUuid,
226 const std::string &_nUuid,
227 const SubscribeOptions &_opts = SubscribeOptions())
228 : ISubscriptionHandler(_pUuid, _nUuid, _opts)
229 {
230 // Parse straight from the buffer (no intermediate string copy).
231 this->SetMsgFactory(
232 [](const char *_data, std::size_t _size,
233 const std::string &/*_type*/) -> std::shared_ptr<ProtoMsg>
234 {
235 auto msgPtr = std::make_shared<T>();
236 if (!msgPtr->ParseFromArray(_data, static_cast<int>(_size)))
237 {
238 std::cerr << "SubscriptionHandler::CreateMsgFromBuffer() error: "
239 << "ParseFromArray failed" << std::endl;
240 }
241 return msgPtr;
242 });
243 }
244
245 // Documentation inherited.
247 const std::string &_data,
248 const std::string &_type) const
249 {
250 // Safe to delegate: the constructor registered a factory.
251 return this->CreateMsgFromBuffer(_data.data(), _data.size(), _type);
252 }
253
254 // Documentation inherited.
256 {
257 return std::string(T().GetTypeName());
258 }
259
262 public: void SetCallback(const MsgCallback<T> &_cb)
263 {
264 this->cb = _cb;
265 }
266
267#ifdef HAVE_ZENOH
272 public: void SetCallback(const MsgCallback<T> &_cb,
274 const FullyQualifiedTopic &_fullyQualifiedTopic)
275 {
276 this->SetCallback(std::move(_cb));
277 this->CreateLivelinessToken(_session, _fullyQualifiedTopic);
278 }
279#endif
280
281 // Documentation inherited.
282 public: bool RunLocalCallback(const ProtoMsg &_msg,
283 const MessageInfo &_info)
284 {
285 // No callback stored.
286 if (!this->cb)
287 {
288 std::cerr << "SubscriptionHandler::RunLocalCallback() error: "
289 << "Callback is NULL" << std::endl;
290 return false;
291 }
292
293 // Check the subscription throttling option.
294 if (!this->UpdateThrottling())
295 return true;
296
297#if GOOGLE_PROTOBUF_VERSION >= 5028000
298 auto msgPtr = google::protobuf::DynamicCastMessage<T>(&_msg);
299#elif GOOGLE_PROTOBUF_VERSION >= 4022000
300 auto msgPtr = google::protobuf::internal::DownCast<const T*>(&_msg);
301#elif GOOGLE_PROTOBUF_VERSION >= 3000000
302 auto msgPtr = google::protobuf::down_cast<const T*>(&_msg);
303#else
304 auto msgPtr = google::protobuf::internal::down_cast<const T*>(&_msg);
305#endif
306
307 // Verify the dynamically casted message is valid
308 if (msgPtr == nullptr)
309 {
310 if (_msg.GetDescriptor() != nullptr)
311 {
312 std::cerr << "SubscriptionHandler::RunLocalCallback() error: "
313 << "Failed to cast the message of the type "
314 << _msg.GetDescriptor()->full_name()
315 << " to the specified type" << '\n';
316 }
317 else
318 {
319 std::cerr << "SubscriptionHandler::RunLocalCallback() error: "
320 << "Failed to cast the message of an unknown type"
321 << " to the specified type" << '\n';
322 }
323 std::cerr.flush();
324 return false;
325 }
326
327 this->cb(*msgPtr, _info);
328 return true;
329 }
330
332 private: MsgCallback<T> cb;
333 };
334
337 template <> class SubscriptionHandler<ProtoMsg>
338 : public ISubscriptionHandler
339 {
340 // Documentation inherited.
341 public: explicit SubscriptionHandler(const std::string &_pUuid,
342 const std::string &_nUuid,
343 const SubscribeOptions &_opts = SubscribeOptions())
344 : ISubscriptionHandler(_pUuid, _nUuid, _opts)
345 {
346 // Look the type up at runtime and parse straight from the buffer
347 // (no intermediate string copy).
348 this->SetMsgFactory(
349 [](const char *_data, std::size_t _size,
351 {
353
354 const google::protobuf::Descriptor *desc =
355 google::protobuf::DescriptorPool::generated_pool()
356 ->FindMessageTypeByName(_type);
357
358 // First, check if we have the descriptor from the generated
359 // proto classes.
360 if (desc)
361 {
362 msgPtr.reset(
363 google::protobuf::MessageFactory::generated_factory()
364 ->GetPrototype(desc)->New());
365 }
366 else
367 {
368 // Fallback on Gazebo Msgs if the message type is not found.
369 msgPtr = gz::msgs::Factory::New(_type);
370 }
371
372 if (!msgPtr)
373 return nullptr;
374
375 if (!msgPtr->ParseFromArray(_data, static_cast<int>(_size)))
376 {
377 std::cerr << "CreateMsgFromBuffer() error: ParseFromArray failed"
378 << std::endl;
379 return nullptr;
380 }
381
382 return msgPtr;
383 });
384 }
385
386 // Documentation inherited.
388 const std::string &_data,
389 const std::string &_type) const
390 {
391 // Safe to delegate: the constructor registered a factory.
392 return this->CreateMsgFromBuffer(_data.data(), _data.size(), _type);
393 }
394
395 // Documentation inherited.
397 {
398 return kGenericMessageType;
399 }
400
403 public: void SetCallback(const MsgCallback<ProtoMsg> &_cb)
404 {
405 this->cb = _cb;
406 }
407
408#ifdef HAVE_ZENOH
413 public: void SetCallback(const MsgCallback<ProtoMsg> &_cb,
415 const FullyQualifiedTopic &_fullyQualifiedTopic)
416 {
417 this->SetCallback(std::move(_cb));
418 this->CreateLivelinessToken(_session, _fullyQualifiedTopic);
419 }
420#endif
421
422 // Documentation inherited.
423 public: bool RunLocalCallback(const ProtoMsg &_msg,
424 const MessageInfo &_info)
425 {
426 // No callback stored.
427 if (!this->cb)
428 {
429 std::cerr << "SubscriptionHandler::RunLocalCallback() "
430 << "error: Callback is NULL" << std::endl;
431 return false;
432 }
433
434 // Check the subscription throttling option.
435 if (!this->UpdateThrottling())
436 return true;
437
438 this->cb(_msg, _info);
439 return true;
440 }
441
443 private: MsgCallback<ProtoMsg> cb;
444 };
445
450 {
458 public: explicit RawSubscriptionHandler(
459 const std::string &_pUuid,
460 const std::string &_nUuid,
461 const std::string &_msgType = kGenericMessageType,
462 const SubscribeOptions &_opts = SubscribeOptions());
463
464 // Documentation inherited
465 public: std::string TypeName() override;
466
470 public: void SetCallback(const RawCallback &_callback);
471
472#ifdef HAVE_ZENOH
477 public: void SetCallback(const RawCallback &_cb,
479 const FullyQualifiedTopic &_fullyQualifiedTopic);
480
485 public: void CreateLivelinessToken(
487 const FullyQualifiedTopic &_fullyQualifiedTopic);
488#endif
489
496 public: bool RunRawCallback(const char *_msgData, const size_t _size,
497 const MessageInfo &_info);
498
501
502 private: class Implementation;
503
504#ifdef _WIN32
505// Disable warning C4251 which is triggered by
506// std::unique_ptr
507#pragma warning(push)
508#pragma warning(disable: 4251)
509#endif
512 private: std::unique_ptr<Implementation> pimpl;
513#ifdef _WIN32
514#pragma warning(pop)
515#endif
516 };
517 }
518}
519
520#endif