diff --git a/include/gz/transport/AdvertiseOptions.hh b/include/gz/transport/AdvertiseOptions.hh index 76f1b4b55..4385f7a49 100644 --- a/include/gz/transport/AdvertiseOptions.hh +++ b/include/gz/transport/AdvertiseOptions.hh @@ -25,94 +25,92 @@ #include "gz/transport/config.hh" #include "gz/transport/Export.hh" -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + // Forward declarations. + class AdvertiseOptionsPrivate; + class AdvertiseMessageOptionsPrivate; + class AdvertiseServiceOptionsPrivate; + + /// \brief This strongly typed enum defines the different options for + /// the scope of a topic/service. + enum class Scope_t { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - // Forward declarations. - class AdvertiseOptionsPrivate; - class AdvertiseMessageOptionsPrivate; - class AdvertiseServiceOptionsPrivate; - - /// \brief This strongly typed enum defines the different options for - /// the scope of a topic/service. - enum class Scope_t - { - /// \brief Topic/service only available to subscribers in the same - /// process as the publisher. - PROCESS, - /// \brief Topic/service only available to subscribers in the same - /// machine as the publisher. - HOST, - /// \brief Topic/service available to any subscriber (default scope). - ALL - }; - - /// \class AdvertiseOptions AdvertiseOptions.hh - /// gz/transport/AdvertiseOptions.hh - /// \brief A class for customizing the publication options for a topic or - /// service advertised. - /// E.g.: Set the scope of a topic/service. - class GZ_TRANSPORT_VISIBLE AdvertiseOptions + /// \brief Topic/service only available to subscribers in the same + /// process as the publisher. + PROCESS, + /// \brief Topic/service only available to subscribers in the same + /// machine as the publisher. + HOST, + /// \brief Topic/service available to any subscriber (default scope). + ALL + }; + + /// \class AdvertiseOptions AdvertiseOptions.hh + /// gz/transport/AdvertiseOptions.hh + /// \brief A class for customizing the publication options for a topic or + /// service advertised. + /// E.g.: Set the scope of a topic/service. + class GZ_TRANSPORT_VISIBLE AdvertiseOptions + { + /// \brief Constructor. + public: AdvertiseOptions(); + + /// \brief Copy constructor. + /// \param[in] _other AdvertiseOptions to copy. + public: AdvertiseOptions(const AdvertiseOptions &_other); + + /// \brief Destructor. + public: virtual ~AdvertiseOptions(); + + /// \brief Assignment operator. + /// \param[in] _other The new AdvertiseOptions. + /// \return A reference to this instance. + public: AdvertiseOptions &operator=(const AdvertiseOptions &_other); + + /// \brief Equality operator. This function checks if the given + /// AdvertiseOptions has identical content to this object. + /// \param[in] _other The options to compare against. + /// \return True if this object matches the provided object. + public: bool operator==(const AdvertiseOptions &_other) const; + + /// \brief Inequality operator. This function checks if the given + /// options do not have identical values to this object. + /// \param[in] _other The options to compare against. + /// \return True if this object does not match the provided object. + public: bool operator!=(const AdvertiseOptions &_other) const; + + /// \brief Stream insertion operator. + /// \param[out] _out The output stream. + /// \param[in] _other AdvertiseOptions to write to the stream. + public: friend std::ostream &operator<<(std::ostream &_out, + const AdvertiseOptions &_other) { - /// \brief Constructor. - public: AdvertiseOptions(); - - /// \brief Copy constructor. - /// \param[in] _other AdvertiseOptions to copy. - public: AdvertiseOptions(const AdvertiseOptions &_other); - - /// \brief Destructor. - public: virtual ~AdvertiseOptions(); - - /// \brief Assignment operator. - /// \param[in] _other The new AdvertiseOptions. - /// \return A reference to this instance. - public: AdvertiseOptions &operator=(const AdvertiseOptions &_other); - - /// \brief Equality operator. This function checks if the given - /// AdvertiseOptions has identical content to this object. - /// \param[in] _other The options to compare against. - /// \return True if this object matches the provided object. - public: bool operator==(const AdvertiseOptions &_other) const; - - /// \brief Inequality operator. This function checks if the given - /// options do not have identical values to this object. - /// \param[in] _other The options to compare against. - /// \return True if this object does not match the provided object. - public: bool operator!=(const AdvertiseOptions &_other) const; - - /// \brief Stream insertion operator. - /// \param[out] _out The output stream. - /// \param[in] _other AdvertiseOptions to write to the stream. - public: friend std::ostream &operator<<(std::ostream &_out, - const AdvertiseOptions &_other) - { - _out << "Advertise options:\n" - << "\tScope: "; - if (_other.Scope() == Scope_t::PROCESS) - _out << "Process" << std::endl; - else if (_other.Scope() == Scope_t::HOST) - _out << "Host" << std::endl; - else - _out << "All" << std::endl; - return _out; - } + _out << "Advertise options:\n" + << "\tScope: "; + if (_other.Scope() == Scope_t::PROCESS) + _out << "Process" << std::endl; + else if (_other.Scope() == Scope_t::HOST) + _out << "Host" << std::endl; + else + _out << "All" << std::endl; + return _out; + } - /// \brief Get the scope used in this topic/service. - /// \return The scope. - /// \sa SetScope. - /// \sa Scope_t. - public: const Scope_t &Scope() const; + /// \brief Get the scope used in this topic/service. + /// \return The scope. + /// \sa SetScope. + /// \sa Scope_t. + public: const Scope_t &Scope() const; - /// \brief Set the scope of the topic or service. - /// \param[in] _scope The new scope. - /// \sa Scope. - /// \sa Scope_t. - public: void SetScope(const Scope_t &_scope); + /// \brief Set the scope of the topic or service. + /// \param[in] _scope The new scope. + /// \sa Scope. + /// \sa Scope_t. + public: void SetScope(const Scope_t &_scope); #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -120,82 +118,82 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal - /// \brief Smart pointer to private data. - private: std::unique_ptr dataPtr; + /// \internal + /// \brief Smart pointer to private data. + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; + }; - /// \brief A class for customizing the publication options for a topic - /// advertised. - /// E.g.: Set the rate of messages per second published. - class GZ_TRANSPORT_VISIBLE AdvertiseMessageOptions - : public AdvertiseOptions + /// \brief A class for customizing the publication options for a topic + /// advertised. + /// E.g.: Set the rate of messages per second published. + class GZ_TRANSPORT_VISIBLE AdvertiseMessageOptions + : public AdvertiseOptions + { + /// \brief Constructor. + public: AdvertiseMessageOptions(); + + /// \brief Copy constructor. + /// \param[in] _other AdvertiseMessageOptions to copy. + public: AdvertiseMessageOptions(const AdvertiseMessageOptions &_other); + + /// \brief Destructor. + public: virtual ~AdvertiseMessageOptions(); + + /// \brief Assignment operator. + /// \param[in] _other The other AdvertiseMessageOptions. + /// \return A reference to this instance. + public: AdvertiseMessageOptions &operator=( + const AdvertiseMessageOptions &_other); + + /// \brief Equality operator. This function checks if the given + /// AdvertiseMessageOptions has identical content to this object. + /// \param[in] _other The options to compare against. + /// \return True if this object matches the provided object. + public: bool operator==(const AdvertiseMessageOptions &_other) const; + + /// \brief Inequality operator. This function checks if the given + /// options do not have identical values to this object. + /// \param[in] _other The options to compare against. + /// \return True if this object does not match the provided object. + public: bool operator!=(const AdvertiseMessageOptions &_other) const; + + /// \brief Stream insertion operator. + /// \param[out] _out The output stream. + /// \param[in] _other AdvertiseMessageOptions to write to the stream. + public: friend std::ostream &operator<<(std::ostream &_out, + const AdvertiseMessageOptions &_other) { - /// \brief Constructor. - public: AdvertiseMessageOptions(); - - /// \brief Copy constructor. - /// \param[in] _other AdvertiseMessageOptions to copy. - public: AdvertiseMessageOptions(const AdvertiseMessageOptions &_other); - - /// \brief Destructor. - public: virtual ~AdvertiseMessageOptions(); - - /// \brief Assignment operator. - /// \param[in] _other The other AdvertiseMessageOptions. - /// \return A reference to this instance. - public: AdvertiseMessageOptions &operator=( - const AdvertiseMessageOptions &_other); - - /// \brief Equality operator. This function checks if the given - /// AdvertiseMessageOptions has identical content to this object. - /// \param[in] _other The options to compare against. - /// \return True if this object matches the provided object. - public: bool operator==(const AdvertiseMessageOptions &_other) const; - - /// \brief Inequality operator. This function checks if the given - /// options do not have identical values to this object. - /// \param[in] _other The options to compare against. - /// \return True if this object does not match the provided object. - public: bool operator!=(const AdvertiseMessageOptions &_other) const; - - /// \brief Stream insertion operator. - /// \param[out] _out The output stream. - /// \param[in] _other AdvertiseMessageOptions to write to the stream. - public: friend std::ostream &operator<<(std::ostream &_out, - const AdvertiseMessageOptions &_other) + _out << static_cast(_other); + if (_other.Throttled()) { - _out << static_cast(_other); - if (_other.Throttled()) - { - _out << "\tThrottled? Yes" << std::endl; - _out << "\tRate: " << _other.MsgsPerSec() << " msgs/sec" << std::endl; - } - else - _out << "\tThrottled? No" << std::endl; - - return _out; + _out << "\tThrottled? Yes" << std::endl; + _out << "\tRate: " << _other.MsgsPerSec() << " msgs/sec" << std::endl; } + else + _out << "\tThrottled? No" << std::endl; + + return _out; + } - /// \brief Whether the publication has been throttled. - /// \return true when the publication is throttled or false otherwise. - /// \sa SetMsgsPerSec - /// \sa MsgsPerSec - public: bool Throttled() const; + /// \brief Whether the publication has been throttled. + /// \return true when the publication is throttled or false otherwise. + /// \sa SetMsgsPerSec + /// \sa MsgsPerSec + public: bool Throttled() const; - /// \brief Get the maximum number of messages per second to be published. - /// \return The maximum number of messages per second. - public: uint64_t MsgsPerSec() const; + /// \brief Get the maximum number of messages per second to be published. + /// \return The maximum number of messages per second. + public: uint64_t MsgsPerSec() const; - /// \brief Set the maximum number of messages per second to be published. - /// Note that we calculate the minimum period of a message based - /// on the msgs/sec rate. Any message sent since the last Publish() - /// and the duration of the period will be discarded. - /// \param[in] _newMsgsPerSec Maximum number of messages per second. - public: void SetMsgsPerSec(const uint64_t _newMsgsPerSec); + /// \brief Set the maximum number of messages per second to be published. + /// Note that we calculate the minimum period of a message based + /// on the msgs/sec rate. Any message sent since the last Publish() + /// and the duration of the period will be discarded. + /// \param[in] _newMsgsPerSec Maximum number of messages per second. + public: void SetMsgsPerSec(const uint64_t _newMsgsPerSec); #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -203,56 +201,56 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal - /// \brief Smart pointer to private data. - private: std::unique_ptr dataPtr; + /// \internal + /// \brief Smart pointer to private data. + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; + }; - /// \brief A class for customizing the publication options for a service - /// advertised. - class GZ_TRANSPORT_VISIBLE AdvertiseServiceOptions - : public AdvertiseOptions + /// \brief A class for customizing the publication options for a service + /// advertised. + class GZ_TRANSPORT_VISIBLE AdvertiseServiceOptions + : public AdvertiseOptions + { + /// \brief Constructor. + public: AdvertiseServiceOptions(); + + /// \brief Copy constructor. + /// \param[in] _other AdvertiseServiceOptions to copy. + public: AdvertiseServiceOptions(const AdvertiseServiceOptions &_other); + + /// \brief Destructor. + public: virtual ~AdvertiseServiceOptions(); + + /// \brief Assignment operator. + /// \param[in] _other The other AdvertiseServiceOptions. + /// \return A reference to this instance. + public: AdvertiseServiceOptions &operator=( + const AdvertiseServiceOptions &_other); + + /// \brief Equality operator. This function checks if the given + /// AdvertiseMessageOptions has identical content to this object. + /// \param[in] _other The options to compare against. + /// \return True if this object matches the provided object. + public: bool operator==(const AdvertiseServiceOptions &_other) const; + + /// \brief Inequality operator. This function checks if the given + /// options do not have identical values to this object. + /// \param[in] _other The options to compare against. + /// \return True if this object does not match the provided object. + public: bool operator!=(const AdvertiseServiceOptions &_other) const; + + /// \brief Stream insertion operator. + /// \param[out] _out The output stream. + /// \param[in] _other AdvertiseServiceOptions to write to the stream. + public: friend std::ostream &operator<<(std::ostream &_out, + const AdvertiseServiceOptions &_other) { - /// \brief Constructor. - public: AdvertiseServiceOptions(); - - /// \brief Copy constructor. - /// \param[in] _other AdvertiseServiceOptions to copy. - public: AdvertiseServiceOptions(const AdvertiseServiceOptions &_other); - - /// \brief Destructor. - public: virtual ~AdvertiseServiceOptions(); - - /// \brief Assignment operator. - /// \param[in] _other The other AdvertiseServiceOptions. - /// \return A reference to this instance. - public: AdvertiseServiceOptions &operator=( - const AdvertiseServiceOptions &_other); - - /// \brief Equality operator. This function checks if the given - /// AdvertiseMessageOptions has identical content to this object. - /// \param[in] _other The options to compare against. - /// \return True if this object matches the provided object. - public: bool operator==(const AdvertiseServiceOptions &_other) const; - - /// \brief Inequality operator. This function checks if the given - /// options do not have identical values to this object. - /// \param[in] _other The options to compare against. - /// \return True if this object does not match the provided object. - public: bool operator!=(const AdvertiseServiceOptions &_other) const; - - /// \brief Stream insertion operator. - /// \param[out] _out The output stream. - /// \param[in] _other AdvertiseServiceOptions to write to the stream. - public: friend std::ostream &operator<<(std::ostream &_out, - const AdvertiseServiceOptions &_other) - { - _out << static_cast(_other); - return _out; - } + _out << static_cast(_other); + return _out; + } #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -260,14 +258,13 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal - /// \brief Smart pointer to private data. - private: std::unique_ptr dataPtr; + /// \internal + /// \brief Smart pointer to private data. + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } -} -#endif + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_ADVERTISEOPTIONS_HH_ diff --git a/include/gz/transport/Clock.hh b/include/gz/transport/Clock.hh index 4155ff268..923c24c78 100644 --- a/include/gz/transport/Clock.hh +++ b/include/gz/transport/Clock.hh @@ -26,104 +26,100 @@ #include "gz/transport/config.hh" #include "gz/transport/Export.hh" -namespace gz +namespace gz::transport { - namespace transport +// Inline bracket to help doxygen filtering. +inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + ////////////////////////////////////////////////// + /// \brief A Clock interface for time tracking + class GZ_TRANSPORT_VISIBLE Clock { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - ////////////////////////////////////////////////// - /// \brief A Clock interface for time tracking - class GZ_TRANSPORT_VISIBLE Clock - { - /// \brief Gets clock time - /// \return Current clock time, in nanoseconds - public: virtual std::chrono::nanoseconds Time() const = 0; - - /// \brief Checks whether the clock is ready to be used or not. - /// \return True if clock is ready to be used, false otherwise - public: virtual bool IsReady() const = 0; - - /// \brief Virtual destructor - public: virtual ~Clock() = default; - }; - - //////////////////////////////////////////////////////////////// - /// \brief A Clock interface implementation that uses - /// gz::msgs::Clock messages distributed across - /// the network - class GZ_TRANSPORT_VISIBLE NetworkClock : public Clock - { - /// \brief Network clock time bases - public: enum class TimeBase : int64_t - { - REAL, ///< Use Clock message `real` time field as time base - SIM, ///< Use Clock message `sim` time field as time base - SYS ///< Use Clock message `sys` time field as time base - }; - - /// \brief Constructor that sets the initial time range option - /// \param[in] _topicName Name of the gz::msgs::Clock type - /// topic to be used - /// \param[in] _timeBase Time base for this clock, defaults to - /// simulation time - public: explicit NetworkClock(const std::string &_topicName, - const TimeBase _timeBase = TimeBase::SIM); - - /// \brief Destructor - public: ~NetworkClock() override; - - // Documentation inherited - public: std::chrono::nanoseconds Time() const override; - - /// \brief Sets and distributes the given clock time - /// \param[in] _time The clock time to be set - /// \remarks No clock arbitration is performed - public: void SetTime(const std::chrono::nanoseconds _time); - - // Documentation inherited - public: bool IsReady() const override; - - /// \internal Implementation of this class - private: class Implementation; - - /// \internal Pointer to the implementation of this class - GZ_UTILS_WARN_IGNORE__DLL_INTERFACE_MISSING - private: std::unique_ptr dataPtr; - GZ_UTILS_WARN_RESUME__DLL_INTERFACE_MISSING - }; - - ////////////////////////////////////////////////// - /// \brief A Clock implementation that leverages host OS time APIs - class GZ_TRANSPORT_VISIBLE WallClock : public Clock - { - /// \brief Returns system wall clock interface - /// \return The sole wall clock instance (a singleton) - public: static WallClock* Instance(); - - // Documentation inherited - public: std::chrono::nanoseconds Time() const override; - - // Documentation inherited - public: bool IsReady() const override; - - /// \internal Private singleton constructor - private: WallClock(); - - /// \brief Destructor - private: ~WallClock() override; - - /// \internal Implementation of this class - private: class Implementation; - - /// \internal Pointer to the implementation of this class - GZ_UTILS_WARN_IGNORE__DLL_INTERFACE_MISSING - private: std::unique_ptr dataPtr; - GZ_UTILS_WARN_RESUME__DLL_INTERFACE_MISSING - }; - } - } -} - -#endif + /// \brief Gets clock time + /// \return Current clock time, in nanoseconds + public: virtual std::chrono::nanoseconds Time() const = 0; + + /// \brief Checks whether the clock is ready to be used or not. + /// \return True if clock is ready to be used, false otherwise + public: virtual bool IsReady() const = 0; + + /// \brief Virtual destructor + public: virtual ~Clock() = default; + }; + + //////////////////////////////////////////////////////////////// + /// \brief A Clock interface implementation that uses + /// gz::msgs::Clock messages distributed across + /// the network + class GZ_TRANSPORT_VISIBLE NetworkClock : public Clock + { + /// \brief Network clock time bases + public: enum class TimeBase : int64_t + { + REAL, ///< Use Clock message `real` time field as time base + SIM, ///< Use Clock message `sim` time field as time base + SYS ///< Use Clock message `sys` time field as time base + }; + + /// \brief Constructor that sets the initial time range option + /// \param[in] _topicName Name of the gz::msgs::Clock type + /// topic to be used + /// \param[in] _timeBase Time base for this clock, defaults to + /// simulation time + public: explicit NetworkClock(const std::string &_topicName, + const TimeBase _timeBase = TimeBase::SIM); + + /// \brief Destructor + public: ~NetworkClock() override; + + // Documentation inherited + public: std::chrono::nanoseconds Time() const override; + + /// \brief Sets and distributes the given clock time + /// \param[in] _time The clock time to be set + /// \remarks No clock arbitration is performed + public: void SetTime(const std::chrono::nanoseconds _time); + + // Documentation inherited + public: bool IsReady() const override; + + /// \internal Implementation of this class + private: class Implementation; + + /// \internal Pointer to the implementation of this class + GZ_UTILS_WARN_IGNORE__DLL_INTERFACE_MISSING + private: std::unique_ptr dataPtr; + GZ_UTILS_WARN_RESUME__DLL_INTERFACE_MISSING + }; + + ////////////////////////////////////////////////// + /// \brief A Clock implementation that leverages host OS time APIs + class GZ_TRANSPORT_VISIBLE WallClock : public Clock + { + /// \brief Returns system wall clock interface + /// \return The sole wall clock instance (a singleton) + public: static WallClock* Instance(); + + // Documentation inherited + public: std::chrono::nanoseconds Time() const override; + + // Documentation inherited + public: bool IsReady() const override; + + /// \internal Private singleton constructor + private: WallClock(); + + /// \brief Destructor + private: ~WallClock() override; + + /// \internal Implementation of this class + private: class Implementation; + + /// \internal Pointer to the implementation of this class + GZ_UTILS_WARN_IGNORE__DLL_INTERFACE_MISSING + private: std::unique_ptr dataPtr; + GZ_UTILS_WARN_RESUME__DLL_INTERFACE_MISSING + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_CLOCK_HH_ diff --git a/include/gz/transport/Discovery.hh b/include/gz/transport/Discovery.hh index 161ebc4e3..87312de91 100644 --- a/include/gz/transport/Discovery.hh +++ b/include/gz/transport/Discovery.hh @@ -17,6 +17,7 @@ #ifndef GZ_TRANSPORT_DISCOVERY_HH_ #define GZ_TRANSPORT_DISCOVERY_HH_ + #include #include @@ -78,1506 +79,1502 @@ #include "gz/transport/TopicStorage.hh" #include "gz/transport/TransportTypes.hh" -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + /// \brief Options for sending discovery messages. + enum class DestinationType { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - /// \brief Options for sending discovery messages. - enum class DestinationType - { - /// \brief Send data via unicast only. - UNICAST, - /// \brief Send data via multicast only. - MULTICAST, - /// \brief Send data via unicast and multicast. - ALL - }; - - // - /// \internal - /// \brief Discovery helper function to poll sockets. - /// \param[in] _sockets Sockets on which to listen. - /// \param[in] _timeout Length of time to poll (milliseconds). - /// \return True if the sockets received a reply. - bool GZ_TRANSPORT_VISIBLE pollSockets( - const std::vector &_sockets, - const int _timeout); - - /// \class Discovery Discovery.hh gz/transport/Discovery.hh - /// \brief A discovery class that implements a distributed topic discovery - /// protocol. It uses UDP multicast for sending/receiving messages and - /// stores updated topic information. The discovery clients can request - /// the discovery of a topic or the advertisement of a local topic. The - /// discovery uses heartbeats to track the state of other peers in the - /// network. The discovery clients can register callbacks to detect when - /// new topics are discovered or topics are no longer available. - template - class Discovery + /// \brief Send data via unicast only. + UNICAST, + /// \brief Send data via multicast only. + MULTICAST, + /// \brief Send data via unicast and multicast. + ALL + }; + + // + /// \internal + /// \brief Discovery helper function to poll sockets. + /// \param[in] _sockets Sockets on which to listen. + /// \param[in] _timeout Length of time to poll (milliseconds). + /// \return True if the sockets received a reply. + bool GZ_TRANSPORT_VISIBLE pollSockets( + const std::vector &_sockets, + const int _timeout); + + /// \class Discovery Discovery.hh gz/transport/Discovery.hh + /// \brief A discovery class that implements a distributed topic discovery + /// protocol. It uses UDP multicast for sending/receiving messages and + /// stores updated topic information. The discovery clients can request + /// the discovery of a topic or the advertisement of a local topic. The + /// discovery uses heartbeats to track the state of other peers in the + /// network. The discovery clients can register callbacks to detect when + /// new topics are discovered or topics are no longer available. + template + class Discovery + { + /// \brief Constructor. + /// \param[in] _pUuid This discovery instance will run inside a + /// transport process. This parameter is the transport process' UUID. + /// \param[in] _ip IP address used for discovery traffic. + /// \param[in] _port UDP port used for discovery traffic. + /// \param[in] _verbose true for enabling verbose mode. + public: Discovery(const std::string &_pUuid, + const std::string &_ip, + const int _port, + const bool _verbose = false) + : multicastGroup(_ip), + port(_port), + hostAddr(determineHost()), + pUuid(_pUuid), + silenceInterval(kDefSilenceInterval), + activityInterval(kDefActivityInterval), + heartbeatInterval(kDefHeartbeatInterval), + connectionCb(nullptr), + disconnectionCb(nullptr), + verbose(_verbose), + initialized(false), + numHeartbeatsUninitialized(0), + exit(false), + enabled(false) { - /// \brief Constructor. - /// \param[in] _pUuid This discovery instance will run inside a - /// transport process. This parameter is the transport process' UUID. - /// \param[in] _ip IP address used for discovery traffic. - /// \param[in] _port UDP port used for discovery traffic. - /// \param[in] _verbose true for enabling verbose mode. - public: Discovery(const std::string &_pUuid, - const std::string &_ip, - const int _port, - const bool _verbose = false) - : multicastGroup(_ip), - port(_port), - hostAddr(determineHost()), - pUuid(_pUuid), - silenceInterval(kDefSilenceInterval), - activityInterval(kDefActivityInterval), - heartbeatInterval(kDefHeartbeatInterval), - connectionCb(nullptr), - disconnectionCb(nullptr), - verbose(_verbose), - initialized(false), - numHeartbeatsUninitialized(0), - exit(false), - enabled(false) + std::string gzIp; + if (env("GZ_IP", gzIp) && !gzIp.empty()) { - std::string gzIp; - if (env("GZ_IP", gzIp) && !gzIp.empty()) - { - this->hostInterfaces = {gzIp}; - } - else - { - // Get the list of network interfaces in this host. - this->hostInterfaces = determineInterfaces(); - } + this->hostInterfaces = {gzIp}; + } + else + { + // Get the list of network interfaces in this host. + this->hostInterfaces = determineInterfaces(); + } #ifdef _WIN32 - WORD wVersionRequested; - WSADATA wsaData; + WORD wVersionRequested; + WSADATA wsaData; - // Request WinSock v2.2. - wVersionRequested = MAKEWORD(2, 2); - // Load WinSock DLL. - if (WSAStartup(wVersionRequested, &wsaData) != 0) - { - std::cerr << "Unable to load WinSock DLL" << std::endl; - return; - } + // Request WinSock v2.2. + wVersionRequested = MAKEWORD(2, 2); + // Load WinSock DLL. + if (WSAStartup(wVersionRequested, &wsaData) != 0) + { + std::cerr << "Unable to load WinSock DLL" << std::endl; + return; + } #endif - for (const auto &netIface : this->hostInterfaces) - { - auto succeed = this->RegisterNetIface(netIface); - - // If the IP address that we're selecting as the main IP address of - // the host is invalid, we change it to 127.0.0.1 . - // This is probably because IGN_IP is set to a wrong value. - if (netIface == this->hostAddr && !succeed) - { - this->RegisterNetIface("127.0.0.1"); - std::cerr << "Did you set the environment variable IGN_IP with a " - << "correct IP address? " << std::endl - << " [" << netIface << "] seems an invalid local IP " - << "address." << std::endl - << " Using 127.0.0.1 as hostname." << std::endl; - this->hostAddr = "127.0.0.1"; - } - } + for (const auto &netIface : this->hostInterfaces) + { + auto succeed = this->RegisterNetIface(netIface); - // Socket option: SO_REUSEADDR. This options is used only for receiving - // data. We can reuse the same socket for receiving multicast data from - // multiple interfaces. We will use the socket at position 0 for - // receiving data. - int reuseAddr = 1; - if (setsockopt(this->sockets.at(0), SOL_SOCKET, SO_REUSEADDR, - reinterpret_cast(&reuseAddr), sizeof(reuseAddr)) != 0) + // If the IP address that we're selecting as the main IP address of + // the host is invalid, we change it to 127.0.0.1 . + // This is probably because IGN_IP is set to a wrong value. + if (netIface == this->hostAddr && !succeed) { - std::cerr << "Error setting socket option (SO_REUSEADDR)." - << std::endl; - return; + this->RegisterNetIface("127.0.0.1"); + std::cerr << "Did you set the environment variable IGN_IP with a " + << "correct IP address? " << std::endl + << " [" << netIface << "] seems an invalid local IP " + << "address." << std::endl + << " Using 127.0.0.1 as hostname." << std::endl; + this->hostAddr = "127.0.0.1"; } + } + + // Socket option: SO_REUSEADDR. This options is used only for receiving + // data. We can reuse the same socket for receiving multicast data from + // multiple interfaces. We will use the socket at position 0 for + // receiving data. + int reuseAddr = 1; + if (setsockopt(this->sockets.at(0), SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast(&reuseAddr), sizeof(reuseAddr)) != 0) + { + std::cerr << "Error setting socket option (SO_REUSEADDR)." + << std::endl; + return; + } #ifdef SO_REUSEPORT - // Socket option: SO_REUSEPORT. This options is used only for receiving - // data. We can reuse the same socket for receiving multicast data from - // multiple interfaces. We will use the socket at position 0 for - // receiving data. - int reusePort = 1; - // cppcheck-suppress ConfigurationNotChecked - if (setsockopt(this->sockets.at(0), SOL_SOCKET, SO_REUSEPORT, - reinterpret_cast(&reusePort), sizeof(reusePort)) != 0) - { - std::cerr << "Error setting socket option (SO_REUSEPORT)." - << std::endl; - return; - } + // Socket option: SO_REUSEPORT. This options is used only for receiving + // data. We can reuse the same socket for receiving multicast data from + // multiple interfaces. We will use the socket at position 0 for + // receiving data. + int reusePort = 1; + // cppcheck-suppress ConfigurationNotChecked + if (setsockopt(this->sockets.at(0), SOL_SOCKET, SO_REUSEPORT, + reinterpret_cast(&reusePort), sizeof(reusePort)) != 0) + { + std::cerr << "Error setting socket option (SO_REUSEPORT)." + << std::endl; + return; + } #endif - // Bind the first socket to the discovery port. - sockaddr_in localAddr; - memset(&localAddr, 0, sizeof(localAddr)); - localAddr.sin_family = AF_INET; - localAddr.sin_addr.s_addr = htonl(INADDR_ANY); - localAddr.sin_port = htons(static_cast(this->port)); - - if (bind(this->sockets.at(0), - reinterpret_cast(&localAddr), sizeof(sockaddr_in)) < 0) - { - std::cerr << "Binding to a local port failed." << std::endl; - return; - } + // Bind the first socket to the discovery port. + sockaddr_in localAddr; + memset(&localAddr, 0, sizeof(localAddr)); + localAddr.sin_family = AF_INET; + localAddr.sin_addr.s_addr = htonl(INADDR_ANY); + localAddr.sin_port = htons(static_cast(this->port)); + + if (bind(this->sockets.at(0), + reinterpret_cast(&localAddr), sizeof(sockaddr_in)) < 0) + { + std::cerr << "Binding to a local port failed." << std::endl; + return; + } - // Set 'mcastAddr' to the multicast discovery group. - memset(&this->mcastAddr, 0, sizeof(this->mcastAddr)); - this->mcastAddr.sin_family = AF_INET; - this->mcastAddr.sin_addr.s_addr = - inet_addr(this->multicastGroup.c_str()); - this->mcastAddr.sin_port = htons(static_cast(this->port)); + // Set 'mcastAddr' to the multicast discovery group. + memset(&this->mcastAddr, 0, sizeof(this->mcastAddr)); + this->mcastAddr.sin_family = AF_INET; + this->mcastAddr.sin_addr.s_addr = + inet_addr(this->multicastGroup.c_str()); + this->mcastAddr.sin_port = htons(static_cast(this->port)); - std::vector relays; - std::string gzRelay = ""; - if (env("GZ_RELAY", gzRelay) && !gzRelay.empty()) - { - relays = transport::split(gzRelay, ':'); - } + std::vector relays; + std::string gzRelay = ""; + if (env("GZ_RELAY", gzRelay) && !gzRelay.empty()) + { + relays = transport::split(gzRelay, ':'); + } - // Register all unicast relays. - for (auto const &relayAddr : relays) - this->AddRelayAddress(relayAddr); + // Register all unicast relays. + for (auto const &relayAddr : relays) + this->AddRelayAddress(relayAddr); - if (this->verbose) - this->PrintCurrentState(); - } + if (this->verbose) + this->PrintCurrentState(); + } - /// \brief Destructor. - public: virtual ~Discovery() + /// \brief Destructor. + public: virtual ~Discovery() + { + // Tell the service thread to terminate. + this->exitMutex.lock(); + this->exit = true; + this->exitMutex.unlock(); + + // Wait for the service threads to finish before exit. + if (this->threadReception.joinable()) + this->threadReception.join(); + + // Broadcast a BYE message to trigger the remote cancellation of + // all our advertised topics. + this->SendMsg(DestinationType::ALL, msgs::Discovery::BYE, + Publisher("", "", this->pUuid, "", AdvertiseOptions())); + + // Close sockets. + for (const auto &sock : this->sockets) { - // Tell the service thread to terminate. - this->exitMutex.lock(); - this->exit = true; - this->exitMutex.unlock(); - - // Wait for the service threads to finish before exit. - if (this->threadReception.joinable()) - this->threadReception.join(); - - // Broadcast a BYE message to trigger the remote cancellation of - // all our advertised topics. - this->SendMsg(DestinationType::ALL, msgs::Discovery::BYE, - Publisher("", "", this->pUuid, "", AdvertiseOptions())); - - // Close sockets. - for (const auto &sock : this->sockets) - { #ifdef _WIN32 - closesocket(sock); - WSACleanup(); + closesocket(sock); + WSACleanup(); #else - close(sock); + close(sock); #endif - } } + } - /// \brief Start the discovery service. You probably want to register the - /// callbacks for receiving discovery notifications before starting the - /// service. - public: void Start() + /// \brief Start the discovery service. You probably want to register the + /// callbacks for receiving discovery notifications before starting the + /// service. + public: void Start() + { { - { - std::lock_guard lock(this->mutex); + std::lock_guard lock(this->mutex); - // The service is already running. - if (this->enabled) - return; + // The service is already running. + if (this->enabled) + return; - this->enabled = true; - } + this->enabled = true; + } - auto now = std::chrono::steady_clock::now(); - this->timeNextHeartbeat = now; - this->timeNextActivity = now; + auto now = std::chrono::steady_clock::now(); + this->timeNextHeartbeat = now; + this->timeNextActivity = now; - // Start the thread that receives discovery information. - this->threadReception = std::thread(&Discovery::RecvMessages, this); - } + // Start the thread that receives discovery information. + this->threadReception = std::thread(&Discovery::RecvMessages, this); + } + + /// \brief Advertise a new message. + /// \param[in] _publisher Publisher's information to advertise. + /// \return True if the method succeed or false otherwise + /// (e.g. if the discovery has not been started). + public: bool Advertise(const Pub &_publisher) + { + DiscoveryCallback cb; - /// \brief Advertise a new message. - /// \param[in] _publisher Publisher's information to advertise. - /// \return True if the method succeed or false otherwise - /// (e.g. if the discovery has not been started). - public: bool Advertise(const Pub &_publisher) { - DiscoveryCallback cb; + std::lock_guard lock(this->mutex); - { - std::lock_guard lock(this->mutex); + if (!this->enabled) + return false; - if (!this->enabled) - return false; + // Add the addressing information (local publisher). + if (!this->info.AddPublisher(_publisher)) + return false; - // Add the addressing information (local publisher). - if (!this->info.AddPublisher(_publisher)) - return false; + cb = this->connectionCb; + } - cb = this->connectionCb; - } + if (cb) + cb(_publisher); - if (cb) - cb(_publisher); + // Only advertise a message outside this process if the scope + // is not 'Process' + if (_publisher.Options().Scope() != Scope_t::PROCESS) + this->SendMsg(DestinationType::ALL, msgs::Discovery::ADVERTISE, + _publisher); - // Only advertise a message outside this process if the scope - // is not 'Process' - if (_publisher.Options().Scope() != Scope_t::PROCESS) - this->SendMsg(DestinationType::ALL, msgs::Discovery::ADVERTISE, - _publisher); + return true; + } - return true; - } + /// \brief Request discovery information about a topic. + /// When using this method, the user might want to use + /// SetConnectionsCb() and SetDisconnectionCb(), that registers callbacks + /// that will be executed when the topic address is discovered or when the + /// node providing the topic is disconnected. + /// \sa SetConnectionsCb. + /// \sa SetDisconnectionsCb. + /// \param[in] _topic Topic name requested. + /// \return True if the method succeeded or false otherwise + /// (e.g. if the discovery has not been started). + public: bool Discover(const std::string &_topic) const + { + DiscoveryCallback cb; + bool found; + Addresses_M addresses; - /// \brief Request discovery information about a topic. - /// When using this method, the user might want to use - /// SetConnectionsCb() and SetDisconnectionCb(), that registers callbacks - /// that will be executed when the topic address is discovered or when the - /// node providing the topic is disconnected. - /// \sa SetConnectionsCb. - /// \sa SetDisconnectionsCb. - /// \param[in] _topic Topic name requested. - /// \return True if the method succeeded or false otherwise - /// (e.g. if the discovery has not been started). - public: bool Discover(const std::string &_topic) const { - DiscoveryCallback cb; - bool found; - Addresses_M addresses; - - { - std::lock_guard lock(this->mutex); + std::lock_guard lock(this->mutex); - if (!this->enabled) - return false; + if (!this->enabled) + return false; - cb = this->connectionCb; - } + cb = this->connectionCb; + } - Pub pub; - pub.SetTopic(_topic); - pub.SetPUuid(this->pUuid); + Pub pub; + pub.SetTopic(_topic); + pub.SetPUuid(this->pUuid); - // Send a discovery request. - this->SendMsg(DestinationType::ALL, msgs::Discovery::SUBSCRIBE, pub); + // Send a discovery request. + this->SendMsg(DestinationType::ALL, msgs::Discovery::SUBSCRIBE, pub); - { - std::lock_guard lock(this->mutex); - found = this->info.Publishers(_topic, addresses); - } + { + std::lock_guard lock(this->mutex); + found = this->info.Publishers(_topic, addresses); + } - if (found) + if (found) + { + // I already have information about this topic. + for (const auto &proc : addresses) { - // I already have information about this topic. - for (const auto &proc : addresses) + for (const auto &node : proc.second) { - for (const auto &node : proc.second) + if (cb) { - if (cb) - { - // Execute the user's callback for a service request. Notice - // that we only execute one callback for preventing receive - // multiple service responses for a single request. - cb(node); - } + // Execute the user's callback for a service request. Notice + // that we only execute one callback for preventing receive + // multiple service responses for a single request. + cb(node); } } } - - return true; } - /// \brief Send the response to a SUBSCRIBERS_REQ message. - /// \param[in] _pub Information to send. - public: void SendSubscribersRep(const MessagePublisher &_pub) const - { - this->SendMsg( - DestinationType::ALL, msgs::Discovery::SUBSCRIBERS_REP, _pub); - } + return true; + } - /// \brief Register a node from this process as a remote subscriber. - /// \param[in] _pub Contains information about the subscriber. - public: void Register(const MessagePublisher &_pub) const - { - this->SendMsg( - DestinationType::ALL, msgs::Discovery::NEW_CONNECTION, _pub); - } + /// \brief Send the response to a SUBSCRIBERS_REQ message. + /// \param[in] _pub Information to send. + public: void SendSubscribersRep(const MessagePublisher &_pub) const + { + this->SendMsg( + DestinationType::ALL, msgs::Discovery::SUBSCRIBERS_REP, _pub); + } - /// \brief Unregister a node from this process as a remote subscriber. - /// \param[in] _pub Contains information about the subscriber. - public: void Unregister(const MessagePublisher &_pub) const - { - this->SendMsg( - DestinationType::ALL, msgs::Discovery::END_CONNECTION, _pub); - } + /// \brief Register a node from this process as a remote subscriber. + /// \param[in] _pub Contains information about the subscriber. + public: void Register(const MessagePublisher &_pub) const + { + this->SendMsg( + DestinationType::ALL, msgs::Discovery::NEW_CONNECTION, _pub); + } - /// \brief Get the discovery information. - /// \return Reference to the discovery information object. - public: const TopicStorage &Info() const - { - std::lock_guard lock(this->mutex); - return this->info; - } + /// \brief Unregister a node from this process as a remote subscriber. + /// \param[in] _pub Contains information about the subscriber. + public: void Unregister(const MessagePublisher &_pub) const + { + this->SendMsg( + DestinationType::ALL, msgs::Discovery::END_CONNECTION, _pub); + } + + /// \brief Get the discovery information. + /// \return Reference to the discovery information object. + public: const TopicStorage &Info() const + { + std::lock_guard lock(this->mutex); + return this->info; + } - /// \brief Get all the publishers' information known for a given topic. - /// \param[in] _topic Topic name. - /// \param[out] _publishers Publishers requested. - /// \return True if the topic is found and there is at least one publisher - public: bool Publishers(const std::string &_topic, - Addresses_M &_publishers) const + /// \brief Get all the publishers' information known for a given topic. + /// \param[in] _topic Topic name. + /// \param[out] _publishers Publishers requested. + /// \return True if the topic is found and there is at least one publisher + public: bool Publishers(const std::string &_topic, + Addresses_M &_publishers) const + { + std::lock_guard lock(this->mutex); + return this->info.Publishers(_topic, _publishers); + } + + /// \brief Get all the subscribers' information known for a given topic. + /// \param[in] _topic Topic name. + /// \param[out] _subscribers All remote subscribers for this topic. + /// \return True if the topic is found and there is at least one publisher + public: bool RemoteSubscribers(const std::string &_topic, + Addresses_M &_subscribers) const + { + std::lock_guard lock(this->mutex); + return this->remoteSubscribers.Publishers(_topic, _subscribers); + } + + /// \brief Unadvertise a new message. Broadcast a discovery + /// message that will cancel all the discovery information for the topic + /// advertised by a specific node. + /// \param[in] _topic Topic name to be unadvertised. + /// \param[in] _nUuid Node UUID. + /// \return True if the method succeeded or false otherwise + /// (e.g. if the discovery has not been started). + public: bool Unadvertise(const std::string &_topic, + const std::string &_nUuid) + { + Pub inf; { std::lock_guard lock(this->mutex); - return this->info.Publishers(_topic, _publishers); + + if (!this->enabled) + return false; + + // Don't do anything if the topic is not advertised by any of my nodes + if (!this->info.Publisher(_topic, this->pUuid, _nUuid, inf)) + return true; + + // Remove the topic information. + this->info.DelPublisherByNode(_topic, this->pUuid, _nUuid); } - /// \brief Get all the subscribers' information known for a given topic. - /// \param[in] _topic Topic name. - /// \param[out] _subscribers All remote subscribers for this topic. - /// \return True if the topic is found and there is at least one publisher - public: bool RemoteSubscribers(const std::string &_topic, - Addresses_M &_subscribers) const + // Only unadvertise a message outside this process if the scope + // is not 'Process'. + if (inf.Options().Scope() != Scope_t::PROCESS) { - std::lock_guard lock(this->mutex); - return this->remoteSubscribers.Publishers(_topic, _subscribers); + this->SendMsg(DestinationType::ALL, + msgs::Discovery::UNADVERTISE, inf); } - /// \brief Unadvertise a new message. Broadcast a discovery - /// message that will cancel all the discovery information for the topic - /// advertised by a specific node. - /// \param[in] _topic Topic name to be unadvertised. - /// \param[in] _nUuid Node UUID. - /// \return True if the method succeeded or false otherwise - /// (e.g. if the discovery has not been started). - public: bool Unadvertise(const std::string &_topic, - const std::string &_nUuid) - { - Pub inf; - { - std::lock_guard lock(this->mutex); + return true; + } - if (!this->enabled) - return false; + /// \brief Get the IP address of this host. + /// \return A string with this host's IP address. + public: std::string HostAddr() const + { + std::lock_guard lock(this->mutex); + return this->hostAddr; + } - // Don't do anything if the topic is not advertised by any of my nodes - if (!this->info.Publisher(_topic, this->pUuid, _nUuid, inf)) - return true; + /// \brief The discovery checks the validity of the topic information + /// every 'activity interval' milliseconds. + /// \sa SetActivityInterval. + /// \return The value in milliseconds. + public: unsigned int ActivityInterval() const + { + std::lock_guard lock(this->mutex); + return this->activityInterval; + } - // Remove the topic information. - this->info.DelPublisherByNode(_topic, this->pUuid, _nUuid); - } + /// \brief Each node broadcasts periodic heartbeats to keep its topic + /// information alive in other nodes. A heartbeat message is sent after + /// 'heartbeat interval' milliseconds. + /// \sa SetHeartbeatInterval. + /// \return The value in milliseconds. + public: unsigned int HeartbeatInterval() const + { + std::lock_guard lock(this->mutex); + return this->heartbeatInterval; + } - // Only unadvertise a message outside this process if the scope - // is not 'Process'. - if (inf.Options().Scope() != Scope_t::PROCESS) - { - this->SendMsg(DestinationType::ALL, - msgs::Discovery::UNADVERTISE, inf); - } + /// \brief Get the maximum time allowed without receiving any discovery + /// information from a node before canceling its entries. + /// \sa SetSilenceInterval. + /// \return The value in milliseconds. + public: unsigned int SilenceInterval() const + { + std::lock_guard lock(this->mutex); + return this->silenceInterval; + } - return true; - } + /// \brief Set the activity interval. + /// \sa ActivityInterval. + /// \param[in] _ms New value in milliseconds. + public: void SetActivityInterval(const unsigned int _ms) + { + std::lock_guard lock(this->mutex); + this->activityInterval = _ms; + } - /// \brief Get the IP address of this host. - /// \return A string with this host's IP address. - public: std::string HostAddr() const - { - std::lock_guard lock(this->mutex); - return this->hostAddr; - } + /// \brief Set the heartbeat interval. + /// \sa HeartbeatInterval. + /// \param[in] _ms New value in milliseconds. + public: void SetHeartbeatInterval(const unsigned int _ms) + { + std::lock_guard lock(this->mutex); + this->heartbeatInterval = _ms; + } - /// \brief The discovery checks the validity of the topic information - /// every 'activity interval' milliseconds. - /// \sa SetActivityInterval. - /// \return The value in milliseconds. - public: unsigned int ActivityInterval() const - { - std::lock_guard lock(this->mutex); - return this->activityInterval; - } + /// \brief Set the maximum silence interval. + /// \sa SilenceInterval. + /// \param[in] _ms New value in milliseconds. + public: void SetSilenceInterval(const unsigned int _ms) + { + std::lock_guard lock(this->mutex); + this->silenceInterval = _ms; + } - /// \brief Each node broadcasts periodic heartbeats to keep its topic - /// information alive in other nodes. A heartbeat message is sent after - /// 'heartbeat interval' milliseconds. - /// \sa SetHeartbeatInterval. - /// \return The value in milliseconds. - public: unsigned int HeartbeatInterval() const - { - std::lock_guard lock(this->mutex); - return this->heartbeatInterval; - } + /// \brief Register a callback to receive discovery connection events. + /// Each time a new topic is connected, the callback will be executed. + /// This version uses a free function as callback. + /// \param[in] _cb Function callback. + public: void ConnectionsCb(const DiscoveryCallback &_cb) + { + std::lock_guard lock(this->mutex); + this->connectionCb = _cb; + } - /// \brief Get the maximum time allowed without receiving any discovery - /// information from a node before canceling its entries. - /// \sa SetSilenceInterval. - /// \return The value in milliseconds. - public: unsigned int SilenceInterval() const - { - std::lock_guard lock(this->mutex); - return this->silenceInterval; - } + /// \brief Register a callback to receive discovery disconnection events. + /// Each time a topic is no longer active, the callback will be executed. + /// This version uses a free function as callback. + /// \param[in] _cb Function callback. + public: void DisconnectionsCb(const DiscoveryCallback &_cb) + { + std::lock_guard lock(this->mutex); + this->disconnectionCb = _cb; + } - /// \brief Set the activity interval. - /// \sa ActivityInterval. - /// \param[in] _ms New value in milliseconds. - public: void SetActivityInterval(const unsigned int _ms) - { - std::lock_guard lock(this->mutex); - this->activityInterval = _ms; - } + /// \brief Register a callback to receive an event when a new remote + /// node subscribes to a topic within this process. + /// \param[in] _cb Function callback. + public: void RegistrationsCb(const DiscoveryCallback &_cb) + { + std::lock_guard lock(this->mutex); + this->registrationCb = _cb; + } - /// \brief Set the heartbeat interval. - /// \sa HeartbeatInterval. - /// \param[in] _ms New value in milliseconds. - public: void SetHeartbeatInterval(const unsigned int _ms) - { - std::lock_guard lock(this->mutex); - this->heartbeatInterval = _ms; - } + /// \brief Register a callback to receive an event when a remote + /// node unsubscribes to a topic within this process. + /// \param[in] _cb Function callback. + public: void UnregistrationsCb(const DiscoveryCallback &_cb) + { + std::lock_guard lock(this->mutex); + this->unregistrationCb = _cb; + } - /// \brief Set the maximum silence interval. - /// \sa SilenceInterval. - /// \param[in] _ms New value in milliseconds. - public: void SetSilenceInterval(const unsigned int _ms) - { - std::lock_guard lock(this->mutex); - this->silenceInterval = _ms; - } + /// \brief Register a callback to receive an event when a node requests + /// the list of remote subscribers. + /// \param[in] _cb Function callback. + public: void SubscribersCb(const std::function &_cb) + { + std::lock_guard lock(this->mutex); + this->subscribersCb = _cb; + } - /// \brief Register a callback to receive discovery connection events. - /// Each time a new topic is connected, the callback will be executed. - /// This version uses a free function as callback. - /// \param[in] _cb Function callback. - public: void ConnectionsCb(const DiscoveryCallback &_cb) + /// \brief Print the current discovery state. + public: void PrintCurrentState() const + { + std::lock_guard lock(this->mutex); + + std::cout << "---------------" << std::endl; + std::cout << std::boolalpha << "Enabled: " + << this->enabled << std::endl; + std::cout << "Discovery state" << std::endl; + std::cout << "\tUUID: " << this->pUuid << std::endl; + std::cout << "Settings" << std::endl; + std::cout << "\tActivity: " << this->activityInterval + << " ms." << std::endl; + std::cout << "\tHeartbeat: " << this->heartbeatInterval + << "ms." << std::endl; + std::cout << "\tSilence: " << this->silenceInterval + << " ms." << std::endl; + std::cout << "Known information:" << std::endl; + this->info.Print(); + + // Used to calculate the elapsed time. + Timestamp now = std::chrono::steady_clock::now(); + + std::cout << "Activity" << std::endl; + if (this->activity.empty()) + std::cout << "\t" << std::endl; + else { - std::lock_guard lock(this->mutex); - this->connectionCb = _cb; - } + for (auto &proc : this->activity) + { + // Elapsed time since the last update from this publisher. + std::chrono::duration elapsed = now - proc.second; - /// \brief Register a callback to receive discovery disconnection events. - /// Each time a topic is no longer active, the callback will be executed. - /// This version uses a free function as callback. - /// \param[in] _cb Function callback. - public: void DisconnectionsCb(const DiscoveryCallback &_cb) - { - std::lock_guard lock(this->mutex); - this->disconnectionCb = _cb; + std::cout << "\t" << proc.first << std::endl; + std::cout << "\t\t" << "Since: " << std::chrono::duration_cast< + std::chrono::milliseconds>(elapsed).count() << " ms. ago. " + << std::endl; + } } + std::cout << "---------------" << std::endl; + } - /// \brief Register a callback to receive an event when a new remote - /// node subscribes to a topic within this process. - /// \param[in] _cb Function callback. - public: void RegistrationsCb(const DiscoveryCallback &_cb) + /// \brief Get the list of topics currently advertised and subscribed + /// in the network. + /// \param[out] _topics List of advertised topics. + public: void TopicList(std::vector &_topics) + { { std::lock_guard lock(this->mutex); - this->registrationCb = _cb; + this->remoteSubscribers.Clear(); } - /// \brief Register a callback to receive an event when a remote - /// node unsubscribes to a topic within this process. - /// \param[in] _cb Function callback. - public: void UnregistrationsCb(const DiscoveryCallback &_cb) + // Request the list of subscribers. + Publisher pub("", "", this->pUuid, "", AdvertiseOptions()); + this->SendMsg( + DestinationType::ALL, msgs::Discovery::SUBSCRIBERS_REQ, pub); + + this->WaitForInit(); + std::lock_guard lock(this->mutex); + this->info.TopicList(_topics); + + std::vector remoteSubs; + this->remoteSubscribers.TopicList(remoteSubs); + + // Add the remote subscribers + for (auto const &t : remoteSubs) { - std::lock_guard lock(this->mutex); - this->unregistrationCb = _cb; + if (std::find(_topics.begin(), _topics.end(), t) == _topics.end()) + { + _topics.push_back(t); + } } + } - /// \brief Register a callback to receive an event when a node requests - /// the list of remote subscribers. - /// \param[in] _cb Function callback. - public: void SubscribersCb(const std::function &_cb) + /// \brief Check if ready/initialized. If not, then wait on the + /// initializedCv condition variable. + public: void WaitForInit() const + { + std::unique_lock lk(this->mutex); + + if (!this->initialized) { - std::lock_guard lock(this->mutex); - this->subscribersCb = _cb; + this->initializedCv.wait(lk, [this]{return this->initialized;}); } + } + + /// \brief Check the validity of the topic information. Each topic update + /// has its own timestamp. This method iterates over the list of topics + /// and invalids the old topics. + private: void UpdateActivity() + { + // The UUIDs of the processes that have expired. + std::vector uuids; + + // A copy of the disconnection callback. + DiscoveryCallback disconnectCb; + + Timestamp now = std::chrono::steady_clock::now(); - /// \brief Print the current discovery state. - public: void PrintCurrentState() const { std::lock_guard lock(this->mutex); - std::cout << "---------------" << std::endl; - std::cout << std::boolalpha << "Enabled: " - << this->enabled << std::endl; - std::cout << "Discovery state" << std::endl; - std::cout << "\tUUID: " << this->pUuid << std::endl; - std::cout << "Settings" << std::endl; - std::cout << "\tActivity: " << this->activityInterval - << " ms." << std::endl; - std::cout << "\tHeartbeat: " << this->heartbeatInterval - << "ms." << std::endl; - std::cout << "\tSilence: " << this->silenceInterval - << " ms." << std::endl; - std::cout << "Known information:" << std::endl; - this->info.Print(); - - // Used to calculate the elapsed time. - Timestamp now = std::chrono::steady_clock::now(); - - std::cout << "Activity" << std::endl; - if (this->activity.empty()) - std::cout << "\t" << std::endl; - else + if (now < this->timeNextActivity) + return; + + disconnectCb = this->disconnectionCb; + + for (auto it = this->activity.cbegin(); it != this->activity.cend();) { - for (auto &proc : this->activity) + // Elapsed time since the last update from this publisher. + auto elapsed = now - it->second; + + // This publisher has expired. + if (std::chrono::duration_cast + (elapsed).count() > this->silenceInterval) { - // Elapsed time since the last update from this publisher. - std::chrono::duration elapsed = now - proc.second; + // Remove all the info entries for this process UUID. + this->info.DelPublishersByProc(it->first); + + uuids.push_back(it->first); - std::cout << "\t" << proc.first << std::endl; - std::cout << "\t\t" << "Since: " << std::chrono::duration_cast< - std::chrono::milliseconds>(elapsed).count() << " ms. ago. " - << std::endl; + // Remove the activity entry. + this->activity.erase(it++); } + else + ++it; } - std::cout << "---------------" << std::endl; + + this->timeNextActivity = std::chrono::steady_clock::now() + + std::chrono::milliseconds(this->activityInterval); } - /// \brief Get the list of topics currently advertised and subscribed - /// in the network. - /// \param[out] _topics List of advertised topics. - public: void TopicList(std::vector &_topics) + if (!disconnectCb) + return; + + // Notify without topic information. This is useful to inform the + // client that a remote node is gone, even if we were not + // interested in its topics. + for (auto const &uuid : uuids) { - { - std::lock_guard lock(this->mutex); - this->remoteSubscribers.Clear(); - } + Pub publisher; + publisher.SetPUuid(uuid); + disconnectCb(publisher); + } + } - // Request the list of subscribers. - Publisher pub("", "", this->pUuid, "", AdvertiseOptions()); - this->SendMsg( - DestinationType::ALL, msgs::Discovery::SUBSCRIBERS_REQ, pub); + /// \brief Broadcast periodic heartbeats. + private: void UpdateHeartbeat() + { + Timestamp now = std::chrono::steady_clock::now(); - this->WaitForInit(); + { std::lock_guard lock(this->mutex); - this->info.TopicList(_topics); - std::vector remoteSubs; - this->remoteSubscribers.TopicList(remoteSubs); - - // Add the remote subscribers - for (auto const &t : remoteSubs) - { - if (std::find(_topics.begin(), _topics.end(), t) == _topics.end()) - { - _topics.push_back(t); - } - } + if (now < this->timeNextHeartbeat) + return; } - /// \brief Check if ready/initialized. If not, then wait on the - /// initializedCv condition variable. - public: void WaitForInit() const + Publisher pub("", "", this->pUuid, "", AdvertiseOptions()); + this->SendMsg(DestinationType::ALL, msgs::Discovery::HEARTBEAT, pub); + + std::map> nodes; { - std::unique_lock lk(this->mutex); + std::lock_guard lock(this->mutex); - if (!this->initialized) + // Re-advertise topics that are advertised inside this process. + this->info.PublishersByProc(this->pUuid, nodes); + } + + for (const auto &topic : nodes) + { + for (const auto &node : topic.second) { - this->initializedCv.wait(lk, [this]{return this->initialized;}); + this->SendMsg(DestinationType::ALL, + msgs::Discovery::ADVERTISE, node); } } - /// \brief Check the validity of the topic information. Each topic update - /// has its own timestamp. This method iterates over the list of topics - /// and invalids the old topics. - private: void UpdateActivity() { - // The UUIDs of the processes that have expired. - std::vector uuids; - - // A copy of the disconnection callback. - DiscoveryCallback disconnectCb; - - Timestamp now = std::chrono::steady_clock::now(); - + std::lock_guard lock(this->mutex); + if (!this->initialized) { - std::lock_guard lock(this->mutex); - - if (now < this->timeNextActivity) - return; - - disconnectCb = this->disconnectionCb; - - for (auto it = this->activity.cbegin(); it != this->activity.cend();) + if (this->numHeartbeatsUninitialized == 2u) { - // Elapsed time since the last update from this publisher. - auto elapsed = now - it->second; - - // This publisher has expired. - if (std::chrono::duration_cast - (elapsed).count() > this->silenceInterval) - { - // Remove all the info entries for this process UUID. - this->info.DelPublishersByProc(it->first); - - uuids.push_back(it->first); + // We consider discovery initialized after two heartbeat cycles. + this->initialized = true; - // Remove the activity entry. - this->activity.erase(it++); - } - else - ++it; + // Notify anyone waiting for the initialization phase to finish. + this->initializedCv.notify_all(); } - - this->timeNextActivity = std::chrono::steady_clock::now() + - std::chrono::milliseconds(this->activityInterval); + ++this->numHeartbeatsUninitialized; } - if (!disconnectCb) - return; - - // Notify without topic information. This is useful to inform the - // client that a remote node is gone, even if we were not - // interested in its topics. - for (auto const &uuid : uuids) - { - Pub publisher; - publisher.SetPUuid(uuid); - disconnectCb(publisher); - } + this->timeNextHeartbeat = std::chrono::steady_clock::now() + + std::chrono::milliseconds(this->heartbeatInterval); } + } + + /// \brief Calculate the next timeout. There are three main activities to + /// perform by the discovery component: + /// 1. Receive discovery messages. + /// 2. Send heartbeats. + /// 3. Maintain the discovery information up to date. + /// + /// Tasks (2) and (3) need to be checked at fixed intervals. This function + /// calculates the next timeout to satisfy (2) and (3). + /// \return A timeout (milliseconds). + private: int NextTimeout() const + { + auto now = std::chrono::steady_clock::now(); + auto timeUntilNextHeartbeat = this->timeNextHeartbeat - now; + auto timeUntilNextActivity = this->timeNextActivity - now; + + int t = static_cast( + std::chrono::duration_cast + (std::min(timeUntilNextHeartbeat, timeUntilNextActivity)).count()); + int t2 = std::min(t, this->kTimeout); + return std::max(t2, 0); + } - /// \brief Broadcast periodic heartbeats. - private: void UpdateHeartbeat() + /// \brief Receive discovery messages. + private: void RecvMessages() + { + bool timeToExit = false; + while (!timeToExit) { - Timestamp now = std::chrono::steady_clock::now(); + // Calculate the timeout. + int timeout = this->NextTimeout(); + if (pollSockets(this->sockets, timeout)) { - std::lock_guard lock(this->mutex); + this->RecvDiscoveryUpdate(); - if (now < this->timeNextHeartbeat) - return; + if (this->verbose) + this->PrintCurrentState(); } - Publisher pub("", "", this->pUuid, "", AdvertiseOptions()); - this->SendMsg(DestinationType::ALL, msgs::Discovery::HEARTBEAT, pub); + this->UpdateHeartbeat(); + this->UpdateActivity(); - std::map> nodes; + // Is it time to exit? { - std::lock_guard lock(this->mutex); - - // Re-advertise topics that are advertised inside this process. - this->info.PublishersByProc(this->pUuid, nodes); + std::lock_guard lock(this->exitMutex); + if (this->exit) + timeToExit = true; } + } + } - for (const auto &topic : nodes) + /// \brief Method in charge of receiving the discovery updates. + private: void RecvDiscoveryUpdate() + { + char rcvStr[Discovery::kMaxRcvStr]; + sockaddr_in clntAddr; + socklen_t addrLen = sizeof(clntAddr); + + int64_t received = recvfrom(this->sockets.at(0), + reinterpret_cast(rcvStr), + this->kMaxRcvStr, 0, + reinterpret_cast(&clntAddr), + reinterpret_cast(&addrLen)); + if (received > 0) + { + uint16_t len = 0; + memcpy(&len, &rcvStr[0], sizeof(len)); + + // Gazebo Transport delimits each discovery message with a + // frame_delimiter that contains byte size information. + // A discovery message has the form: + // + // + // + // Gazebo Transport version < 8 sends a frame delimiter that + // contains the value of sizeof(frame_delimiter) + // + sizeof(frame_body). In other words, the frame_delimiter + // contains a value that represents the total size of the + // frame_body and frame_delimiter in bytes. + // + // Gazebo Transport version >= 8 sends a frame_delimiter + // that contains the value of sizeof(frame_body). In other + // words, the frame_delimiter contains a value that represents + // the total size of only the frame_body. + // + // It is possible that two incompatible versions of Gazebo + // Transport exist on the same network. If we receive an + // unexpected size, then we ignore the message. + + // If-condition for version 8+ + if (len + sizeof(len) == static_cast(received)) { - for (const auto &node : topic.second) - { - this->SendMsg(DestinationType::ALL, - msgs::Discovery::ADVERTISE, node); - } - } + std::string srcAddr = inet_ntoa(clntAddr.sin_addr); + uint16_t srcPort = ntohs(clntAddr.sin_port); - { - std::lock_guard lock(this->mutex); - if (!this->initialized) + if (this->verbose) { - if (this->numHeartbeatsUninitialized == 2u) - { - // We consider discovery initialized after two heartbeat cycles. - this->initialized = true; - - // Notify anyone waiting for the initialization phase to finish. - this->initializedCv.notify_all(); - } - ++this->numHeartbeatsUninitialized; + std::cout << "\nReceived discovery update from " + << srcAddr << ": " << srcPort << std::endl; } - this->timeNextHeartbeat = std::chrono::steady_clock::now() + - std::chrono::milliseconds(this->heartbeatInterval); + this->DispatchDiscoveryMsg(srcAddr, rcvStr + sizeof(len), len); } } + else if (received < 0) + { + std::cerr << "Discovery::RecvDiscoveryUpdate() recvfrom error" + << std::endl; + } + } - /// \brief Calculate the next timeout. There are three main activities to - /// perform by the discovery component: - /// 1. Receive discovery messages. - /// 2. Send heartbeats. - /// 3. Maintain the discovery information up to date. - /// - /// Tasks (2) and (3) need to be checked at fixed intervals. This function - /// calculates the next timeout to satisfy (2) and (3). - /// \return A timeout (milliseconds). - private: int NextTimeout() const + /// \brief Parse a discovery message received via the UDP socket + /// \param[in] _fromIp IP address of the message sender. + /// \param[in] _msg Received message. + /// \param[in] _len Entire length of the package in octets. + private: void DispatchDiscoveryMsg(const std::string &_fromIp, + char *_msg, uint16_t _len) + { + gz::msgs::Discovery msg; + + // Parse the message, and return if parsing failed. Parsing could + // fail when another discovery node is publishing messages using an + // older (or newer) format. + if (!msg.ParseFromArray(_msg, _len)) + return; + + // Discard the message if the wire protocol is different than mine. + if (this->Version() != msg.version()) + return; + + std::string recvPUuid = msg.process_uuid(); + + // Discard our own discovery messages. + if (recvPUuid == this->pUuid) + return; + + // Forwarding summary: + // - From a unicast peer -> to multicast group (with NO_RELAY flag). + // - From multicast group -> to unicast peers (with RELAY flag). + + // If the RELAY flag is set, this discovery message is coming via a + // unicast transmission. In this case, we don't process it, we just + // forward it to the multicast group, and it will be dispatched once + // received there. Note that we also unset the RELAY flag and set the + // NO_RELAY flag, to avoid forwarding the message anymore. + if (msg.has_flags() && msg.flags().relay()) { - auto now = std::chrono::steady_clock::now(); - auto timeUntilNextHeartbeat = this->timeNextHeartbeat - now; - auto timeUntilNextActivity = this->timeNextActivity - now; - - int t = static_cast( - std::chrono::duration_cast - (std::min(timeUntilNextHeartbeat, timeUntilNextActivity)).count()); - int t2 = std::min(t, this->kTimeout); - return std::max(t2, 0); + // Unset the RELAY flag in the header and set the NO_RELAY. + msg.mutable_flags()->set_relay(false); + msg.mutable_flags()->set_no_relay(true); + this->SendMulticast(msg); + + // A unicast peer contacted me. I need to save its address for + // sending future messages in the future. + this->AddRelayAddress(_fromIp); + return; + } + // If we are receiving this discovery message via the multicast channel + // and the NO_RELAY flag is not set, we forward this message via unicast + // to all our relays. Note that this is the most common case, where we + // receive a regular multicast message and we forward it to any remote + // relays. + else if (!msg.has_flags() || !msg.flags().no_relay()) + { + msg.mutable_flags()->set_relay(true); + this->SendUnicast(msg); } - /// \brief Receive discovery messages. - private: void RecvMessages() + bool isSenderLocal = (std::find(this->hostInterfaces.begin(), + this->hostInterfaces.end(), _fromIp) != this->hostInterfaces.end()) || + (_fromIp.find("127.") == 0); + + // Update timestamp and cache the callbacks. + DiscoveryCallback connectCb; + DiscoveryCallback disconnectCb; + DiscoveryCallback registerCb; + DiscoveryCallback unregisterCb; + std::function subscribersReqCb; { - bool timeToExit = false; - while (!timeToExit) + std::lock_guard lock(this->mutex); + this->activity[recvPUuid] = std::chrono::steady_clock::now(); + connectCb = this->connectionCb; + disconnectCb = this->disconnectionCb; + registerCb = this->registrationCb; + unregisterCb = this->unregistrationCb; + subscribersReqCb = this->subscribersCb; + } + + switch (msg.type()) + { + case msgs::Discovery::ADVERTISE: { - // Calculate the timeout. - int timeout = this->NextTimeout(); + // Read the rest of the fields. + Pub publisher; + publisher.SetFromDiscovery(msg); - if (pollSockets(this->sockets, timeout)) + // Check scope of the topic. + if ((publisher.Options().Scope() == Scope_t::PROCESS) || + (publisher.Options().Scope() == Scope_t::HOST && + !isSenderLocal)) { - this->RecvDiscoveryUpdate(); - - if (this->verbose) - this->PrintCurrentState(); + return; } - this->UpdateHeartbeat(); - this->UpdateActivity(); + // Register an advertised address for the topic. + bool added; + { + std::lock_guard lock(this->mutex); + added = this->info.AddPublisher(publisher); + } - // Is it time to exit? + if (added && connectCb) { - std::lock_guard lock(this->exitMutex); - if (this->exit) - timeToExit = true; + // Execute the client's callback. + connectCb(publisher); } - } - } - /// \brief Method in charge of receiving the discovery updates. - private: void RecvDiscoveryUpdate() - { - char rcvStr[Discovery::kMaxRcvStr]; - sockaddr_in clntAddr; - socklen_t addrLen = sizeof(clntAddr); - - int64_t received = recvfrom(this->sockets.at(0), - reinterpret_cast(rcvStr), - this->kMaxRcvStr, 0, - reinterpret_cast(&clntAddr), - reinterpret_cast(&addrLen)); - if (received > 0) + break; + } + case msgs::Discovery::SUBSCRIBE: { - uint16_t len = 0; - memcpy(&len, &rcvStr[0], sizeof(len)); - - // Gazebo Transport delimits each discovery message with a - // frame_delimiter that contains byte size information. - // A discovery message has the form: - // - // - // - // Gazebo Transport version < 8 sends a frame delimiter that - // contains the value of sizeof(frame_delimiter) - // + sizeof(frame_body). In other words, the frame_delimiter - // contains a value that represents the total size of the - // frame_body and frame_delimiter in bytes. - // - // Gazebo Transport version >= 8 sends a frame_delimiter - // that contains the value of sizeof(frame_body). In other - // words, the frame_delimiter contains a value that represents - // the total size of only the frame_body. - // - // It is possible that two incompatible versions of Gazebo - // Transport exist on the same network. If we receive an - // unexpected size, then we ignore the message. - - // If-condition for version 8+ - if (len + sizeof(len) == static_cast(received)) + std::string recvTopic; + // Read the topic information. + if (msg.has_sub()) { - std::string srcAddr = inet_ntoa(clntAddr.sin_addr); - uint16_t srcPort = ntohs(clntAddr.sin_port); + recvTopic = msg.sub().topic(); + } + else + { + std::cerr << "Subscription discovery message is missing " + << "Subscriber information.\n"; + break; + } - if (this->verbose) + // Check if at least one of my nodes advertises the topic requested. + Addresses_M addresses; + { + std::lock_guard lock(this->mutex); + if (!this->info.HasAnyPublishers(recvTopic, this->pUuid)) { - std::cout << "\nReceived discovery update from " - << srcAddr << ": " << srcPort << std::endl; + break; } - this->DispatchDiscoveryMsg(srcAddr, rcvStr + sizeof(len), len); + if (!this->info.Publishers(recvTopic, addresses)) + break; } - } - else if (received < 0) - { - std::cerr << "Discovery::RecvDiscoveryUpdate() recvfrom error" - << std::endl; - } - } - /// \brief Parse a discovery message received via the UDP socket - /// \param[in] _fromIp IP address of the message sender. - /// \param[in] _msg Received message. - /// \param[in] _len Entire length of the package in octets. - private: void DispatchDiscoveryMsg(const std::string &_fromIp, - char *_msg, uint16_t _len) - { - gz::msgs::Discovery msg; + for (const auto &nodeInfo : addresses[this->pUuid]) + { + // Check scope of the topic. + if ((nodeInfo.Options().Scope() == Scope_t::PROCESS) || + (nodeInfo.Options().Scope() == Scope_t::HOST && + !isSenderLocal)) + { + continue; + } - // Parse the message, and return if parsing failed. Parsing could - // fail when another discovery node is publishing messages using an - // older (or newer) format. - if (!msg.ParseFromArray(_msg, _len)) - return; + // Answer an ADVERTISE message. + this->SendMsg(DestinationType::ALL, + msgs::Discovery::ADVERTISE, nodeInfo); + } - // Discard the message if the wire protocol is different than mine. - if (this->Version() != msg.version()) - return; + break; + } + case msgs::Discovery::SUBSCRIBERS_REQ: + { + if (subscribersReqCb) + subscribersReqCb(); - std::string recvPUuid = msg.process_uuid(); + break; + } + case msgs::Discovery::SUBSCRIBERS_REP: + { + // Save the remote subscriber. + Pub publisher; + publisher.SetFromDiscovery(msg); - // Discard our own discovery messages. - if (recvPUuid == this->pUuid) - return; + { + std::lock_guard lock(this->mutex); + this->remoteSubscribers.AddPublisher(publisher); + } + break; + } + case msgs::Discovery::NEW_CONNECTION: + { + // Read the rest of the fields. + Pub publisher; + publisher.SetFromDiscovery(msg); - // Forwarding summary: - // - From a unicast peer -> to multicast group (with NO_RELAY flag). - // - From multicast group -> to unicast peers (with RELAY flag). + if (registerCb) + registerCb(publisher); - // If the RELAY flag is set, this discovery message is coming via a - // unicast transmission. In this case, we don't process it, we just - // forward it to the multicast group, and it will be dispatched once - // received there. Note that we also unset the RELAY flag and set the - // NO_RELAY flag, to avoid forwarding the message anymore. - if (msg.has_flags() && msg.flags().relay()) - { - // Unset the RELAY flag in the header and set the NO_RELAY. - msg.mutable_flags()->set_relay(false); - msg.mutable_flags()->set_no_relay(true); - this->SendMulticast(msg); - - // A unicast peer contacted me. I need to save its address for - // sending future messages in the future. - this->AddRelayAddress(_fromIp); - return; + break; } - // If we are receiving this discovery message via the multicast channel - // and the NO_RELAY flag is not set, we forward this message via unicast - // to all our relays. Note that this is the most common case, where we - // receive a regular multicast message and we forward it to any remote - // relays. - else if (!msg.has_flags() || !msg.flags().no_relay()) + case msgs::Discovery::END_CONNECTION: { - msg.mutable_flags()->set_relay(true); - this->SendUnicast(msg); - } + // Read the rest of the fields. + Pub publisher; + publisher.SetFromDiscovery(msg); - bool isSenderLocal = (std::find(this->hostInterfaces.begin(), - this->hostInterfaces.end(), _fromIp) != this->hostInterfaces.end()) || - (_fromIp.find("127.") == 0); + if (unregisterCb) + unregisterCb(publisher); - // Update timestamp and cache the callbacks. - DiscoveryCallback connectCb; - DiscoveryCallback disconnectCb; - DiscoveryCallback registerCb; - DiscoveryCallback unregisterCb; - std::function subscribersReqCb; + break; + } + case msgs::Discovery::HEARTBEAT: { - std::lock_guard lock(this->mutex); - this->activity[recvPUuid] = std::chrono::steady_clock::now(); - connectCb = this->connectionCb; - disconnectCb = this->disconnectionCb; - registerCb = this->registrationCb; - unregisterCb = this->unregistrationCb; - subscribersReqCb = this->subscribersCb; + // The timestamp has already been updated. + break; } - - switch (msg.type()) + case msgs::Discovery::BYE: { - case msgs::Discovery::ADVERTISE: + // Remove the activity entry for this publisher. { - // Read the rest of the fields. - Pub publisher; - publisher.SetFromDiscovery(msg); - - // Check scope of the topic. - if ((publisher.Options().Scope() == Scope_t::PROCESS) || - (publisher.Options().Scope() == Scope_t::HOST && - !isSenderLocal)) - { - return; - } - - // Register an advertised address for the topic. - bool added; - { - std::lock_guard lock(this->mutex); - added = this->info.AddPublisher(publisher); - } - - if (added && connectCb) - { - // Execute the client's callback. - connectCb(publisher); - } - - break; + std::lock_guard lock(this->mutex); + this->activity.erase(recvPUuid); } - case msgs::Discovery::SUBSCRIBE: - { - std::string recvTopic; - // Read the topic information. - if (msg.has_sub()) - { - recvTopic = msg.sub().topic(); - } - else - { - std::cerr << "Subscription discovery message is missing " - << "Subscriber information.\n"; - break; - } - - // Check if at least one of my nodes advertises the topic requested. - Addresses_M addresses; - { - std::lock_guard lock(this->mutex); - if (!this->info.HasAnyPublishers(recvTopic, this->pUuid)) - { - break; - } - - if (!this->info.Publishers(recvTopic, addresses)) - break; - } - - for (const auto &nodeInfo : addresses[this->pUuid]) - { - // Check scope of the topic. - if ((nodeInfo.Options().Scope() == Scope_t::PROCESS) || - (nodeInfo.Options().Scope() == Scope_t::HOST && - !isSenderLocal)) - { - continue; - } - - // Answer an ADVERTISE message. - this->SendMsg(DestinationType::ALL, - msgs::Discovery::ADVERTISE, nodeInfo); - } - break; - } - case msgs::Discovery::SUBSCRIBERS_REQ: + if (disconnectCb) { - if (subscribersReqCb) - subscribersReqCb(); - - break; + Pub pub; + pub.SetPUuid(recvPUuid); + // Notify the new disconnection. + disconnectCb(pub); } - case msgs::Discovery::SUBSCRIBERS_REP: - { - // Save the remote subscriber. - Pub publisher; - publisher.SetFromDiscovery(msg); - { - std::lock_guard lock(this->mutex); - this->remoteSubscribers.AddPublisher(publisher); - } - break; - } - case msgs::Discovery::NEW_CONNECTION: + // Remove the address entry for this topic. { - // Read the rest of the fields. - Pub publisher; - publisher.SetFromDiscovery(msg); - - if (registerCb) - registerCb(publisher); - - break; + std::lock_guard lock(this->mutex); + this->info.DelPublishersByProc(recvPUuid); } - case msgs::Discovery::END_CONNECTION: - { - // Read the rest of the fields. - Pub publisher; - publisher.SetFromDiscovery(msg); - if (unregisterCb) - unregisterCb(publisher); + break; + } + case msgs::Discovery::UNADVERTISE: + { + // Read the address. + Pub publisher; + publisher.SetFromDiscovery(msg); - break; - } - case msgs::Discovery::HEARTBEAT: + // Check scope of the topic. + if ((publisher.Options().Scope() == Scope_t::PROCESS) || + (publisher.Options().Scope() == Scope_t::HOST && + !isSenderLocal)) { - // The timestamp has already been updated. - break; + return; } - case msgs::Discovery::BYE: - { - // Remove the activity entry for this publisher. - { - std::lock_guard lock(this->mutex); - this->activity.erase(recvPUuid); - } - if (disconnectCb) - { - Pub pub; - pub.SetPUuid(recvPUuid); - // Notify the new disconnection. - disconnectCb(pub); - } - - // Remove the address entry for this topic. - { - std::lock_guard lock(this->mutex); - this->info.DelPublishersByProc(recvPUuid); - } - - break; - } - case msgs::Discovery::UNADVERTISE: + if (disconnectCb) { - // Read the address. - Pub publisher; - publisher.SetFromDiscovery(msg); - - // Check scope of the topic. - if ((publisher.Options().Scope() == Scope_t::PROCESS) || - (publisher.Options().Scope() == Scope_t::HOST && - !isSenderLocal)) - { - return; - } - - if (disconnectCb) - { - // Notify the new disconnection. - disconnectCb(publisher); - } - - // Remove the address entry for this topic. - { - std::lock_guard lock(this->mutex); - this->info.DelPublisherByNode(publisher.Topic(), - publisher.PUuid(), publisher.NUuid()); - } - - break; + // Notify the new disconnection. + disconnectCb(publisher); } - default: + + // Remove the address entry for this topic. { - std::cerr << "Unknown message type [" << msg.type() << "].\n"; - break; + std::lock_guard lock(this->mutex); + this->info.DelPublisherByNode(publisher.Topic(), + publisher.PUuid(), publisher.NUuid()); } + + break; + } + default: + { + std::cerr << "Unknown message type [" << msg.type() << "].\n"; + break; } } + } - /// \brief Broadcast a discovery message. - /// \param[in] _type Message type. - /// \param[in] _pub Publishers's information to send. - /// \param[in] _flags Optional flags. Currently, the flags are not used - /// but they will in the future for specifying things like compression, - /// or encryption. - private: template - void SendMsg(const DestinationType &_destType, - const msgs::Discovery::Type _type, - const T &_pub) const - { - gz::msgs::Discovery discoveryMsg; - discoveryMsg.set_version(this->Version()); - discoveryMsg.set_type(_type); - discoveryMsg.set_process_uuid(this->pUuid); - _pub.FillDiscovery(discoveryMsg); + /// \brief Broadcast a discovery message. + /// \param[in] _type Message type. + /// \param[in] _pub Publishers's information to send. + /// \param[in] _flags Optional flags. Currently, the flags are not used + /// but they will in the future for specifying things like compression, + /// or encryption. + private: template + void SendMsg(const DestinationType &_destType, + const msgs::Discovery::Type _type, + const T &_pub) const + { + gz::msgs::Discovery discoveryMsg; + discoveryMsg.set_version(this->Version()); + discoveryMsg.set_type(_type); + discoveryMsg.set_process_uuid(this->pUuid); + _pub.FillDiscovery(discoveryMsg); - switch (_type) + switch (_type) + { + case msgs::Discovery::ADVERTISE: + case msgs::Discovery::UNADVERTISE: + case msgs::Discovery::NEW_CONNECTION: + case msgs::Discovery::END_CONNECTION: { - case msgs::Discovery::ADVERTISE: - case msgs::Discovery::UNADVERTISE: - case msgs::Discovery::NEW_CONNECTION: - case msgs::Discovery::END_CONNECTION: - { - _pub.FillDiscovery(discoveryMsg); - break; - } - case msgs::Discovery::SUBSCRIBE: - { - discoveryMsg.mutable_sub()->set_topic(_pub.Topic()); - break; - } - case msgs::Discovery::HEARTBEAT: - case msgs::Discovery::BYE: - case msgs::Discovery::SUBSCRIBERS_REQ: - case msgs::Discovery::SUBSCRIBERS_REP: - break; - default: - std::cerr << "Discovery::SendMsg() error: Unrecognized message" - << " type [" << _type << "]" << std::endl; - return; + _pub.FillDiscovery(discoveryMsg); + break; } - - if (_destType == DestinationType::MULTICAST || - _destType == DestinationType::ALL) + case msgs::Discovery::SUBSCRIBE: { - this->SendMulticast(discoveryMsg); + discoveryMsg.mutable_sub()->set_topic(_pub.Topic()); + break; } + case msgs::Discovery::HEARTBEAT: + case msgs::Discovery::BYE: + case msgs::Discovery::SUBSCRIBERS_REQ: + case msgs::Discovery::SUBSCRIBERS_REP: + break; + default: + std::cerr << "Discovery::SendMsg() error: Unrecognized message" + << " type [" << _type << "]" << std::endl; + return; + } - // Send the discovery message to the unicast relays. - if (_destType == DestinationType::UNICAST || - _destType == DestinationType::ALL) - { - // Set the RELAY flag in the header. - discoveryMsg.mutable_flags()->set_relay(true); - this->SendUnicast(discoveryMsg); - } + if (_destType == DestinationType::MULTICAST || + _destType == DestinationType::ALL) + { + this->SendMulticast(discoveryMsg); + } - if (this->verbose) - { - std::cout << "\t* Sending " << msgs::ToString(_type) - << " msg [" << _pub.Topic() << "]" << std::endl; - } + // Send the discovery message to the unicast relays. + if (_destType == DestinationType::UNICAST || + _destType == DestinationType::ALL) + { + // Set the RELAY flag in the header. + discoveryMsg.mutable_flags()->set_relay(true); + this->SendUnicast(discoveryMsg); } - /// \brief Send a discovery message through all unicast relays. - /// \param[in] _msg Discovery message. - private: void SendUnicast(const msgs::Discovery &_msg) const + if (this->verbose) { - uint16_t msgSize; + std::cout << "\t* Sending " << msgs::ToString(_type) + << " msg [" << _pub.Topic() << "]" << std::endl; + } + } + + /// \brief Send a discovery message through all unicast relays. + /// \param[in] _msg Discovery message. + private: void SendUnicast(const msgs::Discovery &_msg) const + { + uint16_t msgSize; #if GOOGLE_PROTOBUF_VERSION >= 3004000 - size_t msgSizeFull = _msg.ByteSizeLong(); + size_t msgSizeFull = _msg.ByteSizeLong(); #else - int msgSizeFull = _msg.ByteSize(); + int msgSizeFull = _msg.ByteSize(); #endif - if (msgSizeFull + sizeof(msgSize) > this->kMaxRcvStr) - { - std::cerr << "Discovery message too large to send. Discovery won't " - << "work. This shouldn't happen.\n"; - return; - } - msgSize = msgSizeFull; + if (msgSizeFull + sizeof(msgSize) > this->kMaxRcvStr) + { + std::cerr << "Discovery message too large to send. Discovery won't " + << "work. This shouldn't happen.\n"; + return; + } + msgSize = msgSizeFull; - uint16_t totalSize = sizeof(msgSize) + msgSize; - char *buffer = static_cast(new char[totalSize]); - memcpy(&buffer[0], &msgSize, sizeof(msgSize)); + uint16_t totalSize = sizeof(msgSize) + msgSize; + char *buffer = static_cast(new char[totalSize]); + memcpy(&buffer[0], &msgSize, sizeof(msgSize)); - if (_msg.SerializeToArray(buffer + sizeof(msgSize), msgSize)) + if (_msg.SerializeToArray(buffer + sizeof(msgSize), msgSize)) + { + // Send the discovery message to the unicast relays. + for (const auto &sockAddr : this->relayAddrs) { - // Send the discovery message to the unicast relays. - for (const auto &sockAddr : this->relayAddrs) + errno = 0; + auto sent = sendto(this->sockets.at(0), + reinterpret_cast( + reinterpret_cast(buffer)), + totalSize, 0, + reinterpret_cast(&sockAddr), + sizeof(sockAddr)); + + if (sent != totalSize) { - errno = 0; - auto sent = sendto(this->sockets.at(0), - reinterpret_cast( - reinterpret_cast(buffer)), - totalSize, 0, - reinterpret_cast(&sockAddr), - sizeof(sockAddr)); - - if (sent != totalSize) - { - std::cerr << "Exception sending a unicast message:" << std::endl; - std::cerr << " Return value: " << sent << std::endl; - std::cerr << " Error code: " << strerror(errno) << std::endl; - break; - } + std::cerr << "Exception sending a unicast message:" << std::endl; + std::cerr << " Return value: " << sent << std::endl; + std::cerr << " Error code: " << strerror(errno) << std::endl; + break; } } - else - { - std::cerr << "Discovery::SendUnicast: Error serializing data." - << std::endl; - } - - delete [] buffer; } - - /// \brief Send a discovery message through the multicast group. - /// \param[in] _msg Discovery message. - private: void SendMulticast(const msgs::Discovery &_msg) const + else { - uint16_t msgSize; + std::cerr << "Discovery::SendUnicast: Error serializing data." + << std::endl; + } + + delete [] buffer; + } + + /// \brief Send a discovery message through the multicast group. + /// \param[in] _msg Discovery message. + private: void SendMulticast(const msgs::Discovery &_msg) const + { + uint16_t msgSize; #if GOOGLE_PROTOBUF_VERSION >= 3004000 - size_t msgSizeFull = _msg.ByteSizeLong(); + size_t msgSizeFull = _msg.ByteSizeLong(); #else - int msgSizeFull = _msg.ByteSize(); + int msgSizeFull = _msg.ByteSize(); #endif - if (msgSizeFull + sizeof(msgSize) > this->kMaxRcvStr) - { - std::cerr << "Discovery message too large to send. Discovery won't " - << "work. This shouldn't happen.\n"; - return; - } + if (msgSizeFull + sizeof(msgSize) > this->kMaxRcvStr) + { + std::cerr << "Discovery message too large to send. Discovery won't " + << "work. This shouldn't happen.\n"; + return; + } - msgSize = msgSizeFull; - uint16_t totalSize = sizeof(msgSize) + msgSize; - char *buffer = static_cast(new char[totalSize]); - memcpy(&buffer[0], &msgSize, sizeof(msgSize)); + msgSize = msgSizeFull; + uint16_t totalSize = sizeof(msgSize) + msgSize; + char *buffer = static_cast(new char[totalSize]); + memcpy(&buffer[0], &msgSize, sizeof(msgSize)); - if (_msg.SerializeToArray(buffer + sizeof(msgSize), msgSize)) + if (_msg.SerializeToArray(buffer + sizeof(msgSize), msgSize)) + { + // Send the discovery message to the multicast group through all the + // sockets. + for (const auto &sock : this->Sockets()) { - // Send the discovery message to the multicast group through all the - // sockets. - for (const auto &sock : this->Sockets()) + errno = 0; + if (sendto(sock, reinterpret_cast( + reinterpret_cast(buffer)), + totalSize, 0, + reinterpret_cast(this->MulticastAddr()), + sizeof(*(this->MulticastAddr()))) != totalSize) { - errno = 0; - if (sendto(sock, reinterpret_cast( - reinterpret_cast(buffer)), - totalSize, 0, - reinterpret_cast(this->MulticastAddr()), - sizeof(*(this->MulticastAddr()))) != totalSize) + // Ignore EPERM and ENOBUFS errors. + // + // See issue #106 + // + // Rationale drawn from: + // + // * https://groups.google.com/forum/#!topic/comp.protocols.tcp-ip/Qou9Sfgr77E + // * https://stackoverflow.com/questions/16555101/sendto-dgrams-do-not-block-for-enobufs-on-osx + if (errno != EPERM && errno != ENOBUFS) { - // Ignore EPERM and ENOBUFS errors. - // - // See issue #106 - // - // Rationale drawn from: - // - // * https://groups.google.com/forum/#!topic/comp.protocols.tcp-ip/Qou9Sfgr77E - // * https://stackoverflow.com/questions/16555101/sendto-dgrams-do-not-block-for-enobufs-on-osx - if (errno != EPERM && errno != ENOBUFS) - { - std::cerr << "Exception sending a multicast message:" - << strerror(errno) << std::endl; - } - break; + std::cerr << "Exception sending a multicast message:" + << strerror(errno) << std::endl; } + break; } } - else - { - std::cerr << "Discovery::SendMulticast: Error serializing data." - << std::endl; - } - - delete [] buffer; } - - /// \brief Get the list of sockets used for discovery. - /// \return The list of sockets. - private: const std::vector &Sockets() const + else { - return this->sockets; + std::cerr << "Discovery::SendMulticast: Error serializing data." + << std::endl; } - /// \brief Get the data structure used for multicast communication. - /// \return The data structure containing the multicast information. - private: const sockaddr_in *MulticastAddr() const - { - return &this->mcastAddr; - } + delete [] buffer; + } - /// \brief Get the discovery protocol version. - /// \return The discovery version. - private: uint8_t Version() const - { - static std::string gzStats; - static int topicStats; + /// \brief Get the list of sockets used for discovery. + /// \return The list of sockets. + private: const std::vector &Sockets() const + { + return this->sockets; + } - if (env("GZ_TRANSPORT_TOPIC_STATISTICS", gzStats) && !gzStats.empty()) - { - topicStats = (gzStats == "1"); - } + /// \brief Get the data structure used for multicast communication. + /// \return The data structure containing the multicast information. + private: const sockaddr_in *MulticastAddr() const + { + return &this->mcastAddr; + } - return this->kWireVersion + (topicStats * 100); - } + /// \brief Get the discovery protocol version. + /// \return The discovery version. + private: uint8_t Version() const + { + static std::string gzStats; + static int topicStats; - /// \brief Register a new network interface in the discovery system. - /// \param[in] _ip IP address to register. - /// \return True when the interface was successfully registered or false - /// otherwise (e.g.: invalid IP address). - private: bool RegisterNetIface(const std::string &_ip) + if (env("GZ_TRANSPORT_TOPIC_STATISTICS", gzStats) && !gzStats.empty()) { - // Make a new socket for sending discovery information. - int sock = static_cast(socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)); - if (sock < 0) - { - std::cerr << "Socket creation failed." << std::endl; - return false; - } + topicStats = (gzStats == "1"); + } - // Socket option: IP_MULTICAST_IF. - // This socket option needs to be applied to each socket used to send - // data. This option selects the source interface for outgoing messages. - struct in_addr ifAddr; - ifAddr.s_addr = inet_addr(_ip.c_str()); - if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, - reinterpret_cast(&ifAddr), sizeof(ifAddr)) != 0) - { - std::cerr << "Error setting socket option (IP_MULTICAST_IF)." - << std::endl; - return false; - } + return this->kWireVersion + (topicStats * 100); + } - this->sockets.push_back(sock); - - // Join the multicast group. We have to do it for each network interface - // but we can do it on the same socket. We will use the socket at - // position 0 for receiving multicast information. - struct ip_mreq group; - group.imr_multiaddr.s_addr = - inet_addr(this->multicastGroup.c_str()); - group.imr_interface.s_addr = inet_addr(_ip.c_str()); - if (setsockopt(this->sockets.at(0), IPPROTO_IP, IP_ADD_MEMBERSHIP, - reinterpret_cast(&group), sizeof(group)) != 0) - { - std::cerr << "Error setting socket option (IP_ADD_MEMBERSHIP)." - << std::endl; - return false; - } + /// \brief Register a new network interface in the discovery system. + /// \param[in] _ip IP address to register. + /// \return True when the interface was successfully registered or false + /// otherwise (e.g.: invalid IP address). + private: bool RegisterNetIface(const std::string &_ip) + { + // Make a new socket for sending discovery information. + int sock = static_cast(socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)); + if (sock < 0) + { + std::cerr << "Socket creation failed." << std::endl; + return false; + } - return true; + // Socket option: IP_MULTICAST_IF. + // This socket option needs to be applied to each socket used to send + // data. This option selects the source interface for outgoing messages. + struct in_addr ifAddr; + ifAddr.s_addr = inet_addr(_ip.c_str()); + if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, + reinterpret_cast(&ifAddr), sizeof(ifAddr)) != 0) + { + std::cerr << "Error setting socket option (IP_MULTICAST_IF)." + << std::endl; + return false; } - /// \brief Register a new relay address. - /// \param[in] _ip New IP address. - private: void AddRelayAddress(const std::string &_ip) + this->sockets.push_back(sock); + + // Join the multicast group. We have to do it for each network interface + // but we can do it on the same socket. We will use the socket at + // position 0 for receiving multicast information. + struct ip_mreq group; + group.imr_multiaddr.s_addr = + inet_addr(this->multicastGroup.c_str()); + group.imr_interface.s_addr = inet_addr(_ip.c_str()); + if (setsockopt(this->sockets.at(0), IPPROTO_IP, IP_ADD_MEMBERSHIP, + reinterpret_cast(&group), sizeof(group)) != 0) { - // Sanity check: Make sure that this IP address is not already saved. - for (auto const &addr : this->relayAddrs) - { - if (addr.sin_addr.s_addr == inet_addr(_ip.c_str())) - return; - } + std::cerr << "Error setting socket option (IP_ADD_MEMBERSHIP)." + << std::endl; + return false; + } - sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = inet_addr(_ip.c_str()); - addr.sin_port = htons(static_cast(this->port)); + return true; + } - this->relayAddrs.push_back(addr); + /// \brief Register a new relay address. + /// \param[in] _ip New IP address. + private: void AddRelayAddress(const std::string &_ip) + { + // Sanity check: Make sure that this IP address is not already saved. + for (auto const &addr : this->relayAddrs) + { + if (addr.sin_addr.s_addr == inet_addr(_ip.c_str())) + return; } - /// \brief Default activity interval value (ms.). - /// \sa ActivityInterval. - /// \sa SetActivityInterval. - private: static const unsigned int kDefActivityInterval = 100; + sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(_ip.c_str()); + addr.sin_port = htons(static_cast(this->port)); - /// \brief Default heartbeat interval value (ms.). - /// \sa HeartbeatInterval. - /// \sa SetHeartbeatInterval. - private: static const unsigned int kDefHeartbeatInterval = 1000; + this->relayAddrs.push_back(addr); + } - /// \brief Default silence interval value (ms.). - /// \sa MaxSilenceInterval. - /// \sa SetMaxSilenceInterval. - private: static const unsigned int kDefSilenceInterval = 3000; + /// \brief Default activity interval value (ms.). + /// \sa ActivityInterval. + /// \sa SetActivityInterval. + private: static const unsigned int kDefActivityInterval = 100; - /// \brief IP Address used for multicast. - private: std::string multicastGroup; + /// \brief Default heartbeat interval value (ms.). + /// \sa HeartbeatInterval. + /// \sa SetHeartbeatInterval. + private: static const unsigned int kDefHeartbeatInterval = 1000; - /// \brief Timeout used for receiving messages (ms.). - private: const int kTimeout = 250; + /// \brief Default silence interval value (ms.). + /// \sa MaxSilenceInterval. + /// \sa SetMaxSilenceInterval. + private: static const unsigned int kDefSilenceInterval = 3000; - /// \brief Longest string to receive. - private: static const uint16_t kMaxRcvStr = - std::numeric_limits::max(); + /// \brief IP Address used for multicast. + private: std::string multicastGroup; - /// \brief Wire protocol version. Bump up the version number if you modify - /// the wire protocol (for discovery or message/service exchange). - private: static const uint8_t kWireVersion = 10; + /// \brief Timeout used for receiving messages (ms.). + private: const int kTimeout = 250; - /// \brief Port used to broadcast the discovery messages. - private: int port; + /// \brief Longest string to receive. + private: static const uint16_t kMaxRcvStr = + std::numeric_limits::max(); - /// \brief Host IP address. - private: std::string hostAddr; + /// \brief Wire protocol version. Bump up the version number if you modify + /// the wire protocol (for discovery or message/service exchange). + private: static const uint8_t kWireVersion = 10; - /// \brief List of host network interfaces. - private: std::vector hostInterfaces; + /// \brief Port used to broadcast the discovery messages. + private: int port; - /// \brief Process UUID. - private: std::string pUuid; + /// \brief Host IP address. + private: std::string hostAddr; - /// \brief Silence interval value (ms.). - /// \sa MaxSilenceInterval. - /// \sa SetMaxSilenceInterval. - private: unsigned int silenceInterval; + /// \brief List of host network interfaces. + private: std::vector hostInterfaces; - /// \brief Activity interval value (ms.). - /// \sa ActivityInterval. - /// \sa SetActivityInterval. - private: unsigned int activityInterval; + /// \brief Process UUID. + private: std::string pUuid; - /// \brief Heartbeat interval value (ms.). - /// \sa HeartbeatInterval. - /// \sa SetHeartbeatInterval. - private: unsigned int heartbeatInterval; + /// \brief Silence interval value (ms.). + /// \sa MaxSilenceInterval. + /// \sa SetMaxSilenceInterval. + private: unsigned int silenceInterval; - /// \brief Callback executed when new topics are discovered. - private: DiscoveryCallback connectionCb; + /// \brief Activity interval value (ms.). + /// \sa ActivityInterval. + /// \sa SetActivityInterval. + private: unsigned int activityInterval; - /// \brief Callback executed when new topics are invalid. - private: DiscoveryCallback disconnectionCb; + /// \brief Heartbeat interval value (ms.). + /// \sa HeartbeatInterval. + /// \sa SetHeartbeatInterval. + private: unsigned int heartbeatInterval; - /// \brief Callback executed when a new remote subscriber is registered. - private: DiscoveryCallback registrationCb; + /// \brief Callback executed when new topics are discovered. + private: DiscoveryCallback connectionCb; - /// \brief Callback executed when a new remote subscriber is unregistered. - private: DiscoveryCallback unregistrationCb; + /// \brief Callback executed when new topics are invalid. + private: DiscoveryCallback disconnectionCb; - /// \brief Callback executed when a SUBSCRIBERS_REQ message is received. - private: std::function subscribersCb; + /// \brief Callback executed when a new remote subscriber is registered. + private: DiscoveryCallback registrationCb; - /// \brief Addressing information. - private: TopicStorage info; + /// \brief Callback executed when a new remote subscriber is unregistered. + private: DiscoveryCallback unregistrationCb; - /// \brief Remote subscribers. - private: TopicStorage remoteSubscribers; + /// \brief Callback executed when a SUBSCRIBERS_REQ message is received. + private: std::function subscribersCb; - /// \brief Activity information. Every time there is a message from a - /// remote node, its activity information is updated. If we do not hear - /// from a node in a while, its entries in 'info' will be invalided. The - /// key is the process uuid. - protected: std::map activity; + /// \brief Addressing information. + private: TopicStorage info; - /// \brief Print discovery information to stdout. - private: bool verbose; + /// \brief Remote subscribers. + private: TopicStorage remoteSubscribers; - /// \brief UDP socket used for sending/receiving discovery messages. - private: std::vector sockets; + /// \brief Activity information. Every time there is a message from a + /// remote node, its activity information is updated. If we do not hear + /// from a node in a while, its entries in 'info' will be invalided. The + /// key is the process uuid. + protected: std::map activity; - /// \brief Internet socket address for sending to the multicast group. - private: sockaddr_in mcastAddr; + /// \brief Print discovery information to stdout. + private: bool verbose; - /// \brief Collection of socket addresses used as remote relays. - private: std::vector relayAddrs; + /// \brief UDP socket used for sending/receiving discovery messages. + private: std::vector sockets; - /// \brief Mutex to guarantee exclusive access between the threads. - private: mutable std::mutex mutex; + /// \brief Internet socket address for sending to the multicast group. + private: sockaddr_in mcastAddr; - /// \brief Thread in charge of receiving and handling incoming messages. - private: std::thread threadReception; + /// \brief Collection of socket addresses used as remote relays. + private: std::vector relayAddrs; - /// \brief Time at which the next heartbeat cycle will be sent. - private: Timestamp timeNextHeartbeat; + /// \brief Mutex to guarantee exclusive access between the threads. + private: mutable std::mutex mutex; - /// \brief Time at which the next activity check will be done. - private: Timestamp timeNextActivity; + /// \brief Thread in charge of receiving and handling incoming messages. + private: std::thread threadReception; - /// \brief Mutex to guarantee exclusive access to the exit variable. - private: std::mutex exitMutex; + /// \brief Time at which the next heartbeat cycle will be sent. + private: Timestamp timeNextHeartbeat; - /// \brief Once the discovery starts, it can take up to - /// HeartbeatInterval milliseconds to discover the existing nodes on the - /// network. This variable is 'false' during the first HeartbeatInterval - /// period and is set to 'true' after that. - private: bool initialized; + /// \brief Time at which the next activity check will be done. + private: Timestamp timeNextActivity; - /// \brief Number of heartbeats sent while discovery is uninitialized. - private: unsigned int numHeartbeatsUninitialized; + /// \brief Mutex to guarantee exclusive access to the exit variable. + private: std::mutex exitMutex; - /// \brief Used to block/unblock until the initialization phase finishes. - private: mutable std::condition_variable initializedCv; + /// \brief Once the discovery starts, it can take up to + /// HeartbeatInterval milliseconds to discover the existing nodes on the + /// network. This variable is 'false' during the first HeartbeatInterval + /// period and is set to 'true' after that. + private: bool initialized; - /// \brief When true, the service thread will finish. - private: bool exit; + /// \brief Number of heartbeats sent while discovery is uninitialized. + private: unsigned int numHeartbeatsUninitialized; - /// \brief When true, the service is enabled. - private: bool enabled; - }; + /// \brief Used to block/unblock until the initialization phase finishes. + private: mutable std::condition_variable initializedCv; - /// \def MsgDiscovery - /// \brief A discovery object for topics. - using MsgDiscovery = Discovery; + /// \brief When true, the service thread will finish. + private: bool exit; - /// \def SrvDiscovery - /// \brief A discovery object for services. - using SrvDiscovery = Discovery; - } - } -} + /// \brief When true, the service is enabled. + private: bool enabled; + }; -#endif + /// \def MsgDiscovery + /// \brief A discovery object for topics. + using MsgDiscovery = Discovery; + + /// \def SrvDiscovery + /// \brief A discovery object for services. + using SrvDiscovery = Discovery; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_DISCOVERY_HH_ diff --git a/include/gz/transport/HandlerStorage.hh b/include/gz/transport/HandlerStorage.hh index 37d3f9f7f..d7b28522b 100644 --- a/include/gz/transport/HandlerStorage.hh +++ b/include/gz/transport/HandlerStorage.hh @@ -26,245 +26,241 @@ #include "gz/transport/config.hh" #include "gz/transport/TransportTypes.hh" -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \class HandlerStorage HandlerStorage.hh + /// gz/transport/HandlerStorage.hh + /// \brief Class to store and manage service call handlers. + template class HandlerStorage { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \class HandlerStorage HandlerStorage.hh - /// gz/transport/HandlerStorage.hh - /// \brief Class to store and manage service call handlers. - template class HandlerStorage - { - /// \brief Stores all the service call data for each topic. The key of - /// _data is the topic name. The value is another map, where the key is - /// the node UUID and the value is a smart pointer to the handler. - /// \TODO(Carlos) review this names and fix them - using UUIDHandler_M = std::map>; - using UUIDHandler_Collection_M = std::map; + /// \brief Stores all the service call data for each topic. The key of + /// _data is the topic name. The value is another map, where the key is + /// the node UUID and the value is a smart pointer to the handler. + /// \TODO(Carlos) review this names and fix them + using UUIDHandler_M = std::map>; + using UUIDHandler_Collection_M = std::map; - /// \brief key is a topic name and value is UUIDHandler_Collection_M - using TopicServiceCalls_M = - std::map; + /// \brief key is a topic name and value is UUIDHandler_Collection_M + using TopicServiceCalls_M = + std::map; - /// \brief Constructor. - public: HandlerStorage() = default; + /// \brief Constructor. + public: HandlerStorage() = default; - /// \brief Destructor. - public: virtual ~HandlerStorage() = default; + /// \brief Destructor. + public: virtual ~HandlerStorage() = default; - /// \brief Get the data handlers for a topic. A request - /// handler stores the callback and types associated to a service call - /// request. - /// \param[in] _topic Topic name. - /// \param[out] _handlers Request handlers. The key of _handlers is the - /// topic name. The value is another map, where the key is the node - /// UUID and the value is a smart pointer to the handler. - /// \return true if the topic contains at least one request. - public: bool Handlers(const std::string &_topic, - std::map >> &_handlers) const - { - if (this->data.find(_topic) == this->data.end()) - return false; + /// \brief Get the data handlers for a topic. A request + /// handler stores the callback and types associated to a service call + /// request. + /// \param[in] _topic Topic name. + /// \param[out] _handlers Request handlers. The key of _handlers is the + /// topic name. The value is another map, where the key is the node + /// UUID and the value is a smart pointer to the handler. + /// \return true if the topic contains at least one request. + public: bool Handlers(const std::string &_topic, + std::map >> &_handlers) const + { + if (this->data.find(_topic) == this->data.end()) + return false; - _handlers = this->data.at(_topic); - return true; - } + _handlers = this->data.at(_topic); + return true; + } - /// \brief Get the first handler for a topic that matches a specific pair - /// of request/response types. - /// \param[in] _topic Topic name. - /// \param[in] _reqTypeName Type of the service request. - /// \param[in] _repTypeName Type of the service response. - /// \param[out] _handler handler. - /// \return true if a handler was found. - public: bool FirstHandler(const std::string &_topic, - const std::string &_reqTypeName, - const std::string &_repTypeName, - std::shared_ptr &_handler) const - { - if (this->data.find(_topic) == this->data.end()) - return false; + /// \brief Get the first handler for a topic that matches a specific pair + /// of request/response types. + /// \param[in] _topic Topic name. + /// \param[in] _reqTypeName Type of the service request. + /// \param[in] _repTypeName Type of the service response. + /// \param[out] _handler handler. + /// \return true if a handler was found. + public: bool FirstHandler(const std::string &_topic, + const std::string &_reqTypeName, + const std::string &_repTypeName, + std::shared_ptr &_handler) const + { + if (this->data.find(_topic) == this->data.end()) + return false; - const auto &m = this->data.at(_topic); - for (const auto &node : m) + const auto &m = this->data.at(_topic); + for (const auto &node : m) + { + for (const auto &handler : node.second) { - for (const auto &handler : node.second) + if (_reqTypeName == handler.second->ReqTypeName() && + _repTypeName == handler.second->RepTypeName()) { - if (_reqTypeName == handler.second->ReqTypeName() && - _repTypeName == handler.second->RepTypeName()) - { - _handler = handler.second; - return true; - } + _handler = handler.second; + return true; } } - return false; } + return false; + } - /// \brief Get the first handler for a topic that matches a specific - /// message type. - /// \param[in] _topic Topic name. - /// \param[in] _msgTypeName Type of the msg in string format. - /// \param[out] _handler handler. - /// \return true if a handler was found. - public: bool FirstHandler(const std::string &_topic, - const std::string &_msgTypeName, - std::shared_ptr &_handler) const - { - if (this->data.find(_topic) == this->data.end()) - return false; + /// \brief Get the first handler for a topic that matches a specific + /// message type. + /// \param[in] _topic Topic name. + /// \param[in] _msgTypeName Type of the msg in string format. + /// \param[out] _handler handler. + /// \return true if a handler was found. + public: bool FirstHandler(const std::string &_topic, + const std::string &_msgTypeName, + std::shared_ptr &_handler) const + { + if (this->data.find(_topic) == this->data.end()) + return false; - const auto &m = this->data.at(_topic); - for (const auto &node : m) + const auto &m = this->data.at(_topic); + for (const auto &node : m) + { + for (const auto &handler : node.second) { - for (const auto &handler : node.second) + if (_msgTypeName == handler.second->TypeName() || + handler.second->TypeName() == kGenericMessageType) { - if (_msgTypeName == handler.second->TypeName() || - handler.second->TypeName() == kGenericMessageType) - { - _handler = handler.second; - return true; - } + _handler = handler.second; + return true; } } - return false; } + return false; + } - /// \brief Get a specific handler. - /// \param[in] _topic Topic name. - /// \param[in] _nUuid Node UUID of the handler. - /// \param[in] _hUuid Handler UUID. - /// \param[out] _handler Handler requested. - /// \return true if the handler was found. - public: bool Handler(const std::string &_topic, - const std::string &_nUuid, - const std::string &_hUuid, - std::shared_ptr &_handler) const - { - if (this->data.find(_topic) == this->data.end()) - return false; - - auto const &m = this->data.at(_topic); - if (m.find(_nUuid) == m.end()) - return false; - - if (m.at(_nUuid).find(_hUuid) == m.at(_nUuid).end()) - return false; + /// \brief Get a specific handler. + /// \param[in] _topic Topic name. + /// \param[in] _nUuid Node UUID of the handler. + /// \param[in] _hUuid Handler UUID. + /// \param[out] _handler Handler requested. + /// \return true if the handler was found. + public: bool Handler(const std::string &_topic, + const std::string &_nUuid, + const std::string &_hUuid, + std::shared_ptr &_handler) const + { + if (this->data.find(_topic) == this->data.end()) + return false; - _handler = m.at(_nUuid).at(_hUuid); - return true; - } + auto const &m = this->data.at(_topic); + if (m.find(_nUuid) == m.end()) + return false; - /// \brief Get a reference to all the handlers. - /// \return All the handlers. - public: TopicServiceCalls_M &AllHandlers() - { - return this->data; - } + if (m.at(_nUuid).find(_hUuid) == m.at(_nUuid).end()) + return false; - /// \brief Add a request handler to a topic. A request handler stores - /// the callback and types associated to a service call request. - /// \param[in] _topic Topic name. - /// \param[in] _nUuid Node's unique identifier. - /// \param[in] _handler Request handler. - public: void AddHandler(const std::string &_topic, - const std::string &_nUuid, - const std::shared_ptr &_handler) - { - // Create the topic entry. - if (this->data.find(_topic) == this->data.end()) - this->data[_topic] = UUIDHandler_Collection_M(); + _handler = m.at(_nUuid).at(_hUuid); + return true; + } - // Create the Node UUID entry. - if (this->data[_topic].find(_nUuid) == this->data[_topic].end()) - this->data[_topic][_nUuid] = UUIDHandler_M(); + /// \brief Get a reference to all the handlers. + /// \return All the handlers. + public: TopicServiceCalls_M &AllHandlers() + { + return this->data; + } - // Add/Replace the Req handler. - this->data[_topic][_nUuid].insert( - std::make_pair(_handler->HandlerUuid(), _handler)); - } + /// \brief Add a request handler to a topic. A request handler stores + /// the callback and types associated to a service call request. + /// \param[in] _topic Topic name. + /// \param[in] _nUuid Node's unique identifier. + /// \param[in] _handler Request handler. + public: void AddHandler(const std::string &_topic, + const std::string &_nUuid, + const std::shared_ptr &_handler) + { + // Create the topic entry. + if (this->data.find(_topic) == this->data.end()) + this->data[_topic] = UUIDHandler_Collection_M(); - /// \brief Return true if we have stored at least one request for the - /// topic. - /// \param[in] _topic Topic name. - /// \return true if we have stored at least one request for the topic. - public: bool HasHandlersForTopic(const std::string &_topic) const - { - if (this->data.find(_topic) == this->data.end()) - return false; + // Create the Node UUID entry. + if (this->data[_topic].find(_nUuid) == this->data[_topic].end()) + this->data[_topic][_nUuid] = UUIDHandler_M(); - return !this->data.at(_topic).empty(); - } + // Add/Replace the Req handler. + this->data[_topic][_nUuid].insert( + std::make_pair(_handler->HandlerUuid(), _handler)); + } - /// \brief Check if a node has at least one handler. - /// \param[in] _topic Topic name. - /// \param[in] _nUuid Node's unique identifier. - /// \return true if the node has at least one handler registered. - public: bool HasHandlersForNode(const std::string &_topic, - const std::string &_nUuid) const - { - if (this->data.find(_topic) == this->data.end()) - return false; + /// \brief Return true if we have stored at least one request for the + /// topic. + /// \param[in] _topic Topic name. + /// \return true if we have stored at least one request for the topic. + public: bool HasHandlersForTopic(const std::string &_topic) const + { + if (this->data.find(_topic) == this->data.end()) + return false; - return this->data.at(_topic).find(_nUuid) != - this->data.at(_topic).end(); - } + return !this->data.at(_topic).empty(); + } - /// \brief Remove a request handler. The node's uuid is used as a key to - /// remove the appropriate request handler. - /// \param[in] _topic Topic name. - /// \param[in] _nUuid Node's unique identifier. - /// \param[in] _reqUuid Request's UUID to remove. - /// \return True when the handler is removed or false otherwise. - public: bool RemoveHandler(const std::string &_topic, - const std::string &_nUuid, - const std::string &_reqUuid) - { - size_t counter = 0; - if (this->data.find(_topic) != this->data.end()) - { - if (this->data[_topic].find(_nUuid) != this->data[_topic].end()) - { - counter = this->data[_topic][_nUuid].erase(_reqUuid); - if (this->data[_topic][_nUuid].empty()) - this->data[_topic].erase(_nUuid); - if (this->data[_topic].empty()) - this->data.erase(_topic); - } - } + /// \brief Check if a node has at least one handler. + /// \param[in] _topic Topic name. + /// \param[in] _nUuid Node's unique identifier. + /// \return true if the node has at least one handler registered. + public: bool HasHandlersForNode(const std::string &_topic, + const std::string &_nUuid) const + { + if (this->data.find(_topic) == this->data.end()) + return false; - return counter > 0; - } + return this->data.at(_topic).find(_nUuid) != + this->data.at(_topic).end(); + } - /// \brief Remove all the handlers from a given node. - /// \param[in] _topic Topic name. - /// \param[in] _nUuid Node's unique identifier. - /// \return True when at least one handler was removed or false otherwise. - public: bool RemoveHandlersForNode(const std::string &_topic, - const std::string &_nUuid) + /// \brief Remove a request handler. The node's uuid is used as a key to + /// remove the appropriate request handler. + /// \param[in] _topic Topic name. + /// \param[in] _nUuid Node's unique identifier. + /// \param[in] _reqUuid Request's UUID to remove. + /// \return True when the handler is removed or false otherwise. + public: bool RemoveHandler(const std::string &_topic, + const std::string &_nUuid, + const std::string &_reqUuid) + { + size_t counter = 0; + if (this->data.find(_topic) != this->data.end()) { - size_t counter = 0; - if (this->data.find(_topic) != this->data.end()) + if (this->data[_topic].find(_nUuid) != this->data[_topic].end()) { - counter = this->data[_topic].erase(_nUuid); + counter = this->data[_topic][_nUuid].erase(_reqUuid); + if (this->data[_topic][_nUuid].empty()) + this->data[_topic].erase(_nUuid); if (this->data[_topic].empty()) this->data.erase(_topic); } + } - return counter > 0; + return counter > 0; + } + + /// \brief Remove all the handlers from a given node. + /// \param[in] _topic Topic name. + /// \param[in] _nUuid Node's unique identifier. + /// \return True when at least one handler was removed or false otherwise. + public: bool RemoveHandlersForNode(const std::string &_topic, + const std::string &_nUuid) + { + size_t counter = 0; + if (this->data.find(_topic) != this->data.end()) + { + counter = this->data[_topic].erase(_nUuid); + if (this->data[_topic].empty()) + this->data.erase(_topic); } - /// \brief Stores all the service call data for each topic. The key of - /// _data is the topic name. The value is another map, where the key is - /// the node UUID and the value is a smart pointer to the handler. - private: TopicServiceCalls_M data; - }; + return counter > 0; } - } -} -#endif + /// \brief Stores all the service call data for each topic. The key of + /// _data is the topic name. The value is another map, where the key is + /// the node UUID and the value is a smart pointer to the handler. + private: TopicServiceCalls_M data; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_HANDLERSTORAGE_HH_ diff --git a/include/gz/transport/Helpers.hh b/include/gz/transport/Helpers.hh index feff06b19..f233e8d79 100644 --- a/include/gz/transport/Helpers.hh +++ b/include/gz/transport/Helpers.hh @@ -43,50 +43,45 @@ #endif #endif -namespace gz +namespace gz::transport { - namespace transport - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \brief Constant used when not interested in throttling. - static const uint64_t kUnthrottled = std::numeric_limits::max(); + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \brief Constant used when not interested in throttling. + static const uint64_t kUnthrottled = std::numeric_limits::max(); - /// \brief Find the environment variable '_name' and return its value. - /// \param[in] _name Name of the environment variable. - /// \param[out] _value Value if the variable was found. - /// \return True if the variable was found or false otherwise. - bool GZ_TRANSPORT_VISIBLE env(const std::string &_name, - std::string &_value); + /// \brief Find the environment variable '_name' and return its value. + /// \param[in] _name Name of the environment variable. + /// \param[out] _value Value if the variable was found. + /// \return True if the variable was found or false otherwise. + bool GZ_TRANSPORT_VISIBLE env(const std::string &_name, + std::string &_value); - /// \brief split at a one character delimiter to get a vector of something - /// \param[in] _orig The string to split - /// \param[in] _delim a character to split the string at - /// \returns vector of split pieces of the string excluding the delimiter - std::vector GZ_TRANSPORT_VISIBLE split( - const std::string &_orig, - char _delim); + /// \brief split at a one character delimiter to get a vector of something + /// \param[in] _orig The string to split + /// \param[in] _delim a character to split the string at + /// \returns vector of split pieces of the string excluding the delimiter + std::vector GZ_TRANSPORT_VISIBLE split( + const std::string &_orig, + char _delim); - /// \brief Portable function to get the id of the current process. - /// \returns id of current process - unsigned int GZ_TRANSPORT_VISIBLE getProcessId(); + /// \brief Portable function to get the id of the current process. + /// \returns id of current process + unsigned int GZ_TRANSPORT_VISIBLE getProcessId(); - // Use safer functions on Windows - #ifdef _MSC_VER - #define gz_strcat strcat_s - #define gz_strcpy strcpy_s - #define gz_sprintf sprintf_s - #define gz_strdup _strdup - #else - #define gz_strcat std::strcat - #define gz_strcpy std::strcpy - #define gz_sprintf std::sprintf - #define gz_strdup strdup - #endif - } - } -} - -// GZ_TRANSPORT_HELPERS_HH_ -#endif + // Use safer functions on Windows + #ifdef _MSC_VER + #define gz_strcat strcat_s + #define gz_strcpy strcpy_s + #define gz_sprintf sprintf_s + #define gz_strdup _strdup + #else + #define gz_strcat std::strcat + #define gz_strcpy std::strcpy + #define gz_sprintf std::sprintf + #define gz_strdup strdup + #endif + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_HELPERS_HH_ diff --git a/include/gz/transport/MessageInfo.hh b/include/gz/transport/MessageInfo.hh index 3458ba59a..d4488d68c 100644 --- a/include/gz/transport/MessageInfo.hh +++ b/include/gz/transport/MessageInfo.hh @@ -24,70 +24,68 @@ #include "gz/transport/config.hh" #include "gz/transport/Export.hh" -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + class MessageInfoPrivate; + + /// \brief A class that provides information about the message received. + class GZ_TRANSPORT_VISIBLE MessageInfo { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - class MessageInfoPrivate; - - /// \brief A class that provides information about the message received. - class GZ_TRANSPORT_VISIBLE MessageInfo - { - /// \brief Default constructor. - public: MessageInfo(); - - /// \brief Explicit copy constructor (The copy constructor is deleted by - /// default due to the use of std::unique_ptr member). - /// \param[in] _other an instance to copy data from - public: MessageInfo(const MessageInfo &_other); - - /// \brief Move constructor - /// \param[in] _other an instance data is moved from - public: MessageInfo(MessageInfo &&_other); // NOLINT - - /// \brief Destructor. - public: ~MessageInfo(); - - /// \brief Get the topic name associated to the message. - /// \return The topic name. - public: const std::string &Topic() const; - - /// \brief Set the topic name associated to the message. - public: void SetTopic(const std::string &_topic); - - /// \brief Get the name of the message type. - /// \return The message type name. - public: const std::string &Type() const; - - /// \brief Set the name of the message type. - /// \param[in] _type the type name to set. - public: void SetType(const std::string &_type); - - /// \brief Get the name of the partition. - /// \return The partition name. - public: const std::string &Partition() const; - - /// \brief Set the partition of the topic the message was on. - /// \param[in] _partition of the topic. - public: void SetPartition(const std::string &_partition); - - /// \brief Set both the topic and the partition from a single string. - /// \param[in] _fullyQualifiedName The topic string with the partition - /// information included. - /// \return true if the topic and partition were set - /// \sa TopicUtils::FullyQualifiedName - public: bool SetTopicAndPartition(const std::string &_fullyQualifiedName); - - /// \brief Whether the message is coming from a node within this process. - /// \return True when intra-process, false otherwise. - public: bool IntraProcess() const; - - /// \brief Set whether this message is intra-process or not. - /// \param[in] _value The intra-process value. - public: void SetIntraProcess(bool _value); + /// \brief Default constructor. + public: MessageInfo(); + + /// \brief Explicit copy constructor (The copy constructor is deleted by + /// default due to the use of std::unique_ptr member). + /// \param[in] _other an instance to copy data from + public: MessageInfo(const MessageInfo &_other); + + /// \brief Move constructor + /// \param[in] _other an instance data is moved from + public: MessageInfo(MessageInfo &&_other); // NOLINT + + /// \brief Destructor. + public: ~MessageInfo(); + + /// \brief Get the topic name associated to the message. + /// \return The topic name. + public: const std::string &Topic() const; + + /// \brief Set the topic name associated to the message. + public: void SetTopic(const std::string &_topic); + + /// \brief Get the name of the message type. + /// \return The message type name. + public: const std::string &Type() const; + + /// \brief Set the name of the message type. + /// \param[in] _type the type name to set. + public: void SetType(const std::string &_type); + + /// \brief Get the name of the partition. + /// \return The partition name. + public: const std::string &Partition() const; + + /// \brief Set the partition of the topic the message was on. + /// \param[in] _partition of the topic. + public: void SetPartition(const std::string &_partition); + + /// \brief Set both the topic and the partition from a single string. + /// \param[in] _fullyQualifiedName The topic string with the partition + /// information included. + /// \return true if the topic and partition were set + /// \sa TopicUtils::FullyQualifiedName + public: bool SetTopicAndPartition(const std::string &_fullyQualifiedName); + + /// \brief Whether the message is coming from a node within this process. + /// \return True when intra-process, false otherwise. + public: bool IntraProcess() const; + + /// \brief Set whether this message is intra-process or not. + /// \param[in] _value The intra-process value. + public: void SetIntraProcess(bool _value); #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -95,14 +93,13 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal - /// \brief Pointer to private data. - protected: std::unique_ptr dataPtr; + /// \internal + /// \brief Pointer to private data. + protected: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } -} -#endif + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_MESSAGEINFO_HH_ diff --git a/include/gz/transport/NetUtils.hh b/include/gz/transport/NetUtils.hh index 2732ebc28..baaa3f10a 100644 --- a/include/gz/transport/NetUtils.hh +++ b/include/gz/transport/NetUtils.hh @@ -24,50 +24,46 @@ #include "gz/transport/config.hh" #include "gz/transport/Export.hh" -namespace gz +namespace gz::transport { - namespace transport - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \brief Determine if an IP is private. - /// Reference: https://github.com/ros/ros_comm/blob/hydro-devel/clients/ - /// roscpp/src/libros/network.cpp - /// \param[in] _ip Input IP address. - /// \return true if the IP address is private. - bool isPrivateIP(const char *_ip); + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \brief Determine if an IP is private. + /// Reference: https://github.com/ros/ros_comm/blob/hydro-devel/clients/ + /// roscpp/src/libros/network.cpp + /// \param[in] _ip Input IP address. + /// \return true if the IP address is private. + bool isPrivateIP(const char *_ip); - /// \brief Determine if an IP is private. - /// \param[in] _hostname Hostname - /// \param[out] _ip IP associated to the input hostname. - /// \return 0 when success. - int hostnameToIp(char *_hostname, std::string &_ip); + /// \brief Determine if an IP is private. + /// \param[in] _hostname Hostname + /// \param[out] _ip IP associated to the input hostname. + /// \return 0 when success. + int hostnameToIp(char *_hostname, std::string &_ip); - /// \brief Determine IP or hostname. - /// Reference: https://github.com/ros/ros_comm/blob/hydro-devel/clients/ - /// roscpp/src/libros/network.cpp - /// \return The IP or hostname of this host. - std::string GZ_TRANSPORT_VISIBLE determineHost(); + /// \brief Determine IP or hostname. + /// Reference: https://github.com/ros/ros_comm/blob/hydro-devel/clients/ + /// roscpp/src/libros/network.cpp + /// \return The IP or hostname of this host. + std::string GZ_TRANSPORT_VISIBLE determineHost(); - /// \brief Determine the list of network interfaces for this machine. - /// Reference: https://github.com/ros/ros_comm/blob/hydro-devel/clients/ - /// roscpp/src/libros/network.cpp - /// \return The list of network interfaces. - std::vector GZ_TRANSPORT_VISIBLE determineInterfaces(); + /// \brief Determine the list of network interfaces for this machine. + /// Reference: https://github.com/ros/ros_comm/blob/hydro-devel/clients/ + /// roscpp/src/libros/network.cpp + /// \return The list of network interfaces. + std::vector GZ_TRANSPORT_VISIBLE determineInterfaces(); - /// \brief Determine the computer's hostname. - /// \return The computer's hostname. - std::string GZ_TRANSPORT_VISIBLE hostname(); + /// \brief Determine the computer's hostname. + /// \return The computer's hostname. + std::string GZ_TRANSPORT_VISIBLE hostname(); - /// \brief Determine your login name. - /// \return Name used to gain access to the computer. - /// On linux and Mac only, if determination - /// of your login name failes then a string of the form "error-UUID" - /// is returned where UUID is a universally unique identifier. - std::string GZ_TRANSPORT_VISIBLE username(); - } - } -} - -#endif + /// \brief Determine your login name. + /// \return Name used to gain access to the computer. + /// On linux and Mac only, if determination + /// of your login name failes then a string of the form "error-UUID" + /// is returned where UUID is a universally unique identifier. + std::string GZ_TRANSPORT_VISIBLE username(); + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_NETUTILS_HH_ diff --git a/include/gz/transport/Node.hh b/include/gz/transport/Node.hh index f4eb284b4..304c5211b 100644 --- a/include/gz/transport/Node.hh +++ b/include/gz/transport/Node.hh @@ -40,749 +40,747 @@ #include "gz/transport/TopicUtils.hh" #include "gz/transport/TransportTypes.hh" -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + // Forward declarations. + class NodePrivate; + + /// \brief Get the capacity of the buffer (High Water Mark) + /// that stores incoming Gazebo Transport messages. Note that this is a + /// global queue shared by all subscribers within the same process. + /// \return The capacity of the buffer storing incoming messages (units are + /// messages). A value of 0 indicates an unlimited buffer and -1 + /// that the socket cannot be queried. The default buffer size is + /// contained in the #kDefaultRcvHwm variable. + /// If the buffer is set to unlimited, then your buffer will grow until + /// you run out of memory (and probably crash). + /// If your buffer reaches the maximum capacity data will be dropped. + int GZ_TRANSPORT_VISIBLE rcvHwm(); + + /// \brief Get the capacity of the buffer (High Water Mark) + /// that stores outgoing Gazebo Transport messages. Note that this is a + /// global queue shared by all publishers within the same process. + /// \return The capacity of the buffer storing outgoing messages (units are + /// messages). A value of 0 indicates an unlimited buffer and -1 + /// that the socket cannot be queried. The default buffer size is + /// contained in the #kDefaultSndHwm variable. + /// If the buffer is set to unlimited, then your buffer will grow until + /// you run out of memory (and probably crash). + /// If your buffer reaches the maximum capacity data will be dropped. + int GZ_TRANSPORT_VISIBLE sndHwm(); + + /// \brief Block the current thread until a SIGINT or SIGTERM is received. + /// Note that this function registers a signal handler. Do not use this + /// function if you want to manage yourself SIGINT/SIGTERM. + void GZ_TRANSPORT_VISIBLE waitForShutdown(); + + /// \class Node Node.hh gz/transport/Node.hh + /// \brief A class that allows a client to communicate with other peers. + /// There are two main communication modes: pub/sub messages and service + /// calls. + class GZ_TRANSPORT_VISIBLE Node { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - // Forward declarations. - class NodePrivate; - - /// \brief Get the capacity of the buffer (High Water Mark) - /// that stores incoming Gazebo Transport messages. Note that this is a - /// global queue shared by all subscribers within the same process. - /// \return The capacity of the buffer storing incoming messages (units are - /// messages). A value of 0 indicates an unlimited buffer and -1 - /// that the socket cannot be queried. The default buffer size is - /// contained in the #kDefaultRcvHwm variable. - /// If the buffer is set to unlimited, then your buffer will grow until - /// you run out of memory (and probably crash). - /// If your buffer reaches the maximum capacity data will be dropped. - int GZ_TRANSPORT_VISIBLE rcvHwm(); - - /// \brief Get the capacity of the buffer (High Water Mark) - /// that stores outgoing Gazebo Transport messages. Note that this is a - /// global queue shared by all publishers within the same process. - /// \return The capacity of the buffer storing outgoing messages (units are - /// messages). A value of 0 indicates an unlimited buffer and -1 - /// that the socket cannot be queried. The default buffer size is - /// contained in the #kDefaultSndHwm variable. - /// If the buffer is set to unlimited, then your buffer will grow until - /// you run out of memory (and probably crash). - /// If your buffer reaches the maximum capacity data will be dropped. - int GZ_TRANSPORT_VISIBLE sndHwm(); - - /// \brief Block the current thread until a SIGINT or SIGTERM is received. - /// Note that this function registers a signal handler. Do not use this - /// function if you want to manage yourself SIGINT/SIGTERM. - void GZ_TRANSPORT_VISIBLE waitForShutdown(); - - /// \class Node Node.hh gz/transport/Node.hh - /// \brief A class that allows a client to communicate with other peers. - /// There are two main communication modes: pub/sub messages and service - /// calls. - class GZ_TRANSPORT_VISIBLE Node + class PublisherPrivate; + + /// \brief A class that is used to store information about an + /// advertised publisher. An instance of this class is returned + /// from Node::Advertise, and should be used in subsequent + /// Node::Publisher::Publish calls. + /// + /// ## Pseudo code example ## + /// + /// auto pub = myNode.Advertise("topic_name"); + /// if (pub) + /// { + /// MsgType msg; + /// + /// // Note that this version of Publish will copy the message + /// // when publishing to interprocess subscribers. + /// pub.Publish(msg); + /// } + public: class GZ_TRANSPORT_VISIBLE Publisher { - class PublisherPrivate; + /// \brief Default constructor. + public: Publisher(); - /// \brief A class that is used to store information about an - /// advertised publisher. An instance of this class is returned - /// from Node::Advertise, and should be used in subsequent - /// Node::Publisher::Publish calls. + /// \brief Constructor. + /// \param[in] _publisher A message publisher. + public: explicit Publisher(const MessagePublisher &_publisher); + + /// \brief Destructor. + public: virtual ~Publisher(); + + /// \brief Allows this class to be evaluated as a boolean. + /// \return True if valid + /// \sa Valid + public: operator bool(); + + /// \brief Allows this class to be evaluated as a boolean (const). + /// \return True if valid + /// \sa Valid + public: operator bool() const; + + /// \brief Return true if valid information, such as a non-empty + /// topic name, is present. + /// \return True if this object can be used in Publish() calls. + public: bool Valid() const; + + /// \brief Publish a message. This function will copy the message + /// when publishing to interprocess subscribers. This copy is + /// necessary to facilitate asynchronous publication. + /// \param[in] _msg A google::protobuf message. + /// \return true when success. + public: bool Publish(const ProtoMsg &_msg); + + /// \brief Publish a raw pre-serialized message. + /// + /// \warning This function is only intended for advanced users. The + /// standard publishing function, Publish(const ProtoMsg &_msg), will + /// ensure that your message is correctly serialized. It is strongly + /// recommended that you use the standard publishing function unless + /// there is a specific reason for using this one (e.g. you are + /// forwarding or playing back data instead of serializing/deserializing + /// it). We currently only support the serialization scheme of protobuf. /// - /// ## Pseudo code example ## + /// \warning This function will copy the message data when + /// publishing to remote subscribers (interprocess communication). /// - /// auto pub = myNode.Advertise("topic_name"); - /// if (pub) - /// { - /// MsgType msg; + /// \note This function will deserialize the message when sending it to + /// local (intraprocess) subscribers. /// - /// // Note that this version of Publish will copy the message - /// // when publishing to interprocess subscribers. - /// pub.Publish(msg); - /// } - public: class GZ_TRANSPORT_VISIBLE Publisher - { - /// \brief Default constructor. - public: Publisher(); - - /// \brief Constructor. - /// \param[in] _publisher A message publisher. - public: explicit Publisher(const MessagePublisher &_publisher); - - /// \brief Destructor. - public: virtual ~Publisher(); - - /// \brief Allows this class to be evaluated as a boolean. - /// \return True if valid - /// \sa Valid - public: operator bool(); - - /// \brief Allows this class to be evaluated as a boolean (const). - /// \return True if valid - /// \sa Valid - public: operator bool() const; - - /// \brief Return true if valid information, such as a non-empty - /// topic name, is present. - /// \return True if this object can be used in Publish() calls. - public: bool Valid() const; - - /// \brief Publish a message. This function will copy the message - /// when publishing to interprocess subscribers. This copy is - /// necessary to facilitate asynchronous publication. - /// \param[in] _msg A google::protobuf message. - /// \return true when success. - public: bool Publish(const ProtoMsg &_msg); - - /// \brief Publish a raw pre-serialized message. - /// - /// \warning This function is only intended for advanced users. The - /// standard publishing function, Publish(const ProtoMsg &_msg), will - /// ensure that your message is correctly serialized. It is strongly - /// recommended that you use the standard publishing function unless - /// there is a specific reason for using this one (e.g. you are - /// forwarding or playing back data instead of serializing/deserializing - /// it). We currently only support the serialization scheme of protobuf. - /// - /// \warning This function will copy the message data when - /// publishing to remote subscribers (interprocess communication). - /// - /// \note This function will deserialize the message when sending it to - /// local (intraprocess) subscribers. - /// - /// \param[in] _msgData A std::string that represents a - /// serialized google::protobuf message. - /// \param[in] _msgType A std::string that contains the message type - /// name. - /// \return true when success. - public: bool PublishRaw( - const std::string &_msgData, - const std::string &_msgType); - - /// \brief Check if message publication is throttled. If so, verify - /// whether the next message should be published or not. - /// - /// This may be used to skip resource or time-intensive operations - /// in the case that the message won't be published. - /// - /// \return true if the message should be published or false otherwise. - /// Additionally always returns true if the topic is not throttled. - public: bool ThrottledUpdateReady() const; - - /// \brief Check if message publication is throttled. If so, verify - /// whether the next message should be published or not. - /// \return true if the message should be published or false otherwise. - private: bool UpdateThrottling(); - - /// \brief Return true if this publisher has subscribers. - /// \return True if subscribers have connected to this publisher. - public: bool HasConnections() const; - - /// \internal - /// \brief Smart pointer to private data. - /// This is std::shared_ptr because we want to trigger the destructor - /// only once: when all references to PublisherPrivate are out of scope. - /// The destructor of PublisherPrivate unadvertise the topic. + /// \param[in] _msgData A std::string that represents a + /// serialized google::protobuf message. + /// \param[in] _msgType A std::string that contains the message type + /// name. + /// \return true when success. + public: bool PublishRaw( + const std::string &_msgData, + const std::string &_msgType); + + /// \brief Check if message publication is throttled. If so, verify + /// whether the next message should be published or not. + /// + /// This may be used to skip resource or time-intensive operations + /// in the case that the message won't be published. + /// + /// \return true if the message should be published or false otherwise. + /// Additionally always returns true if the topic is not throttled. + public: bool ThrottledUpdateReady() const; + + /// \brief Check if message publication is throttled. If so, verify + /// whether the next message should be published or not. + /// \return true if the message should be published or false otherwise. + private: bool UpdateThrottling(); + + /// \brief Return true if this publisher has subscribers. + /// \return True if subscribers have connected to this publisher. + public: bool HasConnections() const; + + /// \internal + /// \brief Smart pointer to private data. + /// This is std::shared_ptr because we want to trigger the destructor + /// only once: when all references to PublisherPrivate are out of scope. + /// The destructor of PublisherPrivate unadvertise the topic. #ifdef _WIN32 // Disable warning C4251 which is triggered by // std::shared_ptr #pragma warning(push) #pragma warning(disable: 4251) #endif - private: std::shared_ptr dataPtr; + private: std::shared_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; + }; + + public: Node(); + + /// \brief Constructor. + /// \param[in] _options Node options. + public: explicit Node(const NodeOptions &_options); + + /// \brief Destructor. + public: virtual ~Node(); + + /// \brief Advertise a new topic. If a topic is currently advertised, + /// you cannot advertise it a second time (regardless of its type). + /// \param[in] _topic Topic name to be advertised. + /// \param[in] _options Advertise options. + /// \return A PublisherId, which can be used in Node::Publish calls. + /// The PublisherId also acts as boolean, where true occurs if the topic + /// was succesfully advertised. + /// \sa AdvertiseOptions. + public: template + Node::Publisher Advertise( + const std::string &_topic, + const AdvertiseMessageOptions &_options = AdvertiseMessageOptions()); + + /// \brief Advertise a new topic. If a topic is currently advertised, + /// you cannot advertise it a second time (regardless of its type). + /// \param[in] _topic Topic name to be advertised. + /// \param[in] _msgTypeName Name of the message type that will be + /// published on the topic. The message type name can be retrieved + /// from a protobuf message using the GetTypeName() function. + /// \param[in] _options Advertise options. + /// \return A PublisherId, which can be used in Node::Publish calls. + /// The PublisherId also acts as boolean, where true occurs if the topic + /// was succesfully advertised. + /// \sa AdvertiseOptions. + public: Node::Publisher Advertise( + const std::string &_topic, + const std::string &_msgTypeName, + const AdvertiseMessageOptions &_options = AdvertiseMessageOptions()); + + /// \brief Get the list of topics advertised by this node. + /// \return A vector containing all the topics advertised by this node. + public: std::vector AdvertisedTopics() const; + + /// \brief Subscribe to a topic registering a callback. + /// Note that this callback does not include any message information. + /// In this version the callback is a free function. + /// \param[in] _topic Topic to be subscribed. + /// \param[in] _callback Pointer to the callback function with the + /// following parameters: + /// * _msg Protobuf message containing a new topic update. + /// \param[in] _opts Subscription options. + /// \return true when successfully subscribed or false otherwise. + public: template + bool Subscribe( + const std::string &_topic, + void(*_callback)(const MessageT &_msg), + const SubscribeOptions &_opts = SubscribeOptions()); - public: Node(); + /// \brief Subscribe to a topic registering a callback. + /// Note that this callback does not include any message information. + /// In this version the callback is a lamda function. + /// \param[in] _topic Topic to be subscribed. + /// \param[in] _callback Lambda function with the following parameters: + /// * _msg Protobuf message containing a new topic update. + /// \param[in] _opts Subscription options. + /// \return true when successfully subscribed or false otherwise. + public: template + bool Subscribe( + const std::string &_topic, + std::function _callback, + const SubscribeOptions &_opts = SubscribeOptions()); - /// \brief Constructor. - /// \param[in] _options Node options. - public: explicit Node(const NodeOptions &_options); + /// \brief Subscribe to a topic registering a callback. + /// Note that this callback does not include any message information. + /// In this version the callback is a member function. + /// \param[in] _topic Topic to be subscribed. + /// \param[in] _callback Pointer to the callback function with the + /// following parameters: + /// * _msg Protobuf message containing a new topic update. + /// \param[in] _obj Instance containing the member function. + /// \param[in] _opts Subscription options. + /// \return true when successfully subscribed or false otherwise. + public: template + bool Subscribe( + const std::string &_topic, + void(ClassT::*_callback)(const MessageT &_msg), + ClassT *_obj, + const SubscribeOptions &_opts = SubscribeOptions()); - /// \brief Destructor. - public: virtual ~Node(); - - /// \brief Advertise a new topic. If a topic is currently advertised, - /// you cannot advertise it a second time (regardless of its type). - /// \param[in] _topic Topic name to be advertised. - /// \param[in] _options Advertise options. - /// \return A PublisherId, which can be used in Node::Publish calls. - /// The PublisherId also acts as boolean, where true occurs if the topic - /// was succesfully advertised. - /// \sa AdvertiseOptions. - public: template - Node::Publisher Advertise( - const std::string &_topic, - const AdvertiseMessageOptions &_options = AdvertiseMessageOptions()); - - /// \brief Advertise a new topic. If a topic is currently advertised, - /// you cannot advertise it a second time (regardless of its type). - /// \param[in] _topic Topic name to be advertised. - /// \param[in] _msgTypeName Name of the message type that will be - /// published on the topic. The message type name can be retrieved - /// from a protobuf message using the GetTypeName() function. - /// \param[in] _options Advertise options. - /// \return A PublisherId, which can be used in Node::Publish calls. - /// The PublisherId also acts as boolean, where true occurs if the topic - /// was succesfully advertised. - /// \sa AdvertiseOptions. - public: Node::Publisher Advertise( - const std::string &_topic, - const std::string &_msgTypeName, - const AdvertiseMessageOptions &_options = AdvertiseMessageOptions()); - - /// \brief Get the list of topics advertised by this node. - /// \return A vector containing all the topics advertised by this node. - public: std::vector AdvertisedTopics() const; - - /// \brief Subscribe to a topic registering a callback. - /// Note that this callback does not include any message information. - /// In this version the callback is a free function. - /// \param[in] _topic Topic to be subscribed. - /// \param[in] _callback Pointer to the callback function with the - /// following parameters: - /// * _msg Protobuf message containing a new topic update. - /// \param[in] _opts Subscription options. - /// \return true when successfully subscribed or false otherwise. - public: template - bool Subscribe( - const std::string &_topic, - void(*_callback)(const MessageT &_msg), - const SubscribeOptions &_opts = SubscribeOptions()); - - /// \brief Subscribe to a topic registering a callback. - /// Note that this callback does not include any message information. - /// In this version the callback is a lamda function. - /// \param[in] _topic Topic to be subscribed. - /// \param[in] _callback Lambda function with the following parameters: - /// * _msg Protobuf message containing a new topic update. - /// \param[in] _opts Subscription options. - /// \return true when successfully subscribed or false otherwise. - public: template - bool Subscribe( - const std::string &_topic, - std::function _callback, - const SubscribeOptions &_opts = SubscribeOptions()); - - /// \brief Subscribe to a topic registering a callback. - /// Note that this callback does not include any message information. - /// In this version the callback is a member function. - /// \param[in] _topic Topic to be subscribed. - /// \param[in] _callback Pointer to the callback function with the - /// following parameters: - /// * _msg Protobuf message containing a new topic update. - /// \param[in] _obj Instance containing the member function. - /// \param[in] _opts Subscription options. - /// \return true when successfully subscribed or false otherwise. - public: template - bool Subscribe( - const std::string &_topic, - void(ClassT::*_callback)(const MessageT &_msg), - ClassT *_obj, - const SubscribeOptions &_opts = SubscribeOptions()); - - /// \brief Subscribe to a topic registering a callback. - /// Note that this callback includes message information. - /// In this version the callback is a free function. - /// \param[in] _topic Topic to be subscribed. - /// \param[in] _callback Pointer to the callback function with the - /// following parameters: - /// * _msg Protobuf message containing a new topic update. - /// * _info Message information (e.g.: topic name). - /// \param[in] _opts Subscription options. - /// \return true when successfully subscribed or false otherwise. - public: template - bool Subscribe( - const std::string &_topic, - void(*_callback)(const MessageT &_msg, const MessageInfo &_info), - const SubscribeOptions &_opts = SubscribeOptions()); - - /// \brief Subscribe to a topic registering a callback. - /// Note that this callback includes message information. - /// In this version the callback is a lamda function. - /// \param[in] _topic Topic to be subscribed. - /// \param[in] _callback Lambda function with the following parameters: - /// * _msg Protobuf message containing a new topic update. - /// * _info Message information (e.g.: topic name). - /// \param[in] _opts Subscription options. - /// \return true when successfully subscribed or false otherwise. - public: template - bool Subscribe( - const std::string &_topic, - std::function _callback, - const SubscribeOptions &_opts = SubscribeOptions()); - - /// \brief Subscribe to a topic registering a callback. - /// Note that this callback includes message information. - /// In this version the callback is a member function. - /// \param[in] _topic Topic to be subscribed. - /// \param[in] _callback Pointer to the callback function with the - /// following parameters: - /// * _msg Protobuf message containing a new topic update. - /// * _info Message information (e.g.: topic name). - /// \param[in] _obj Instance containing the member function. - /// \param[in] _opts Subscription options. - /// \return true when successfully subscribed or false otherwise. - public: template - bool Subscribe( - const std::string &_topic, - void(ClassT::*_callback)(const MessageT &_msg, - const MessageInfo &_info), - ClassT *_obj, - const SubscribeOptions &_opts = SubscribeOptions()); - - /// \brief Get the list of topics subscribed by this node. Note that - /// we might be interested in one topic but we still don't know the - /// address of a publisher. - /// \return A vector containing the subscribed topics (even if we do not - /// have an address for a particular topic yet). - public: std::vector SubscribedTopics() const; - - /// \brief Unsubscribe from a topic. - /// \param[in] _topic Topic name to be unsubscribed. - /// \return true when successfully unsubscribed or false otherwise. - public: bool Unsubscribe(const std::string &_topic); - - /// \brief Advertise a new service. - /// In this version the callback is a plain function pointer. - /// \param[in] _topic Topic name associated to the service. - /// \param[in] _callback Callback to handle the service request with the - /// following parameters: - /// * _request Protobuf message containing the request. - /// * _reply Protobuf message containing the response. - /// * Returns Service call result. - /// \param[in] _options Advertise options. - /// \return true when the topic has been successfully advertised or - /// false otherwise. - /// \sa AdvertiseOptions. - public: template - bool Advertise( - const std::string &_topic, - bool(*_callback)(const RequestT &_request, ReplyT &_reply), - const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); - - /// \brief Advertise a new service without input parameter. - /// In this version the callback is a free function. - /// \param[in] _topic Topic name associated to the service. - /// \param[in] _callback Callback to handle the service request with the - /// following parameters: - /// * _reply Protobuf message containing the response. - /// * Returns Service call result. - /// \param[in] _options Advertise options. - /// \return true when the topic has been successfully advertised or - /// false otherwise. - /// \sa AdvertiseOptions. - public: template - bool Advertise( - const std::string &_topic, - bool(*_callback)(ReplyT &_reply), - const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); - - /// \brief Advertise a new service without any output parameter. - /// In this version the callback is a free function. - /// \param[in] _topic Topic name associated to the service. - /// \param[in] _callback Callback to handle the service request with the - /// following parameters: - /// * _request Protobuf message containing the request. - /// \param[in] _options Advertise options. - /// \return true when the topic has been successfully advertised or - /// false otherwise. - /// \sa AdvertiseOptions. - public: template - bool Advertise( - const std::string &_topic, - void(*_callback)(const RequestT &_request), - const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); - - /// \brief Advertise a new service. - /// In this version the callback is a lambda function. - /// \param[in] _topic Topic name associated to the service. - /// \param[in] _callback Callback to handle the service request with the - /// following parameters: - /// * _request Protobuf message containing the request. - /// * _reply Protobuf message containing the response. - /// * Returns Service call result. - /// \param[in] _options Advertise options. - /// \return true when the topic has been successfully advertised or - /// false otherwise. - /// \sa AdvertiseOptions. - public: template - bool Advertise( - const std::string &_topic, - std::function _callback, - const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); - - /// \brief Advertise a new service without input parameter. - /// In this version the callback is a lambda function. - /// \param[in] _topic Topic name associated to the service. - /// \param[in] _callback Callback to handle the service request with the - /// following parameters: - /// * _reply Protobuf message containing the response. - /// * Returns Service call result. - /// \param[in] _options Advertise options. - /// \return true when the topic has been successfully advertised or - /// false otherwise. - /// \sa AdvertiseOptions. - public: template - bool Advertise( - const std::string &_topic, - std::function &_callback, - const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); - - /// \brief Advertise a new service without any output parameter. - /// In this version the callback is a lambda function. - /// \param[in] _topic Topic name associated to the service. - /// \param[in] _callback Callback to handle the service request with the - /// following parameters: - /// * _request Protobuf message containing the request. - /// \param[in] _options Advertise options. - /// \return true when the topic has been successfully advertised or - /// false otherwise. - /// \sa AdvertiseOptions. - public: template - bool Advertise( - const std::string &_topic, - std::function &_callback, - const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); - - /// \brief Advertise a new service. - /// In this version the callback is a member function. - /// \param[in] _topic Topic name associated to the service. - /// \param[in] _callback Callback to handle the service request with the - /// following parameters: - /// * _request Protobuf message containing the request. - /// * _reply Protobuf message containing the response. - /// * Returns Service call result. - /// \param[in] _obj Instance containing the member function. - /// \param[in] _options Advertise options. - /// \return true when the topic has been successfully advertised or - /// false otherwise. - /// \sa AdvertiseOptions. - public: template - bool Advertise( - const std::string &_topic, - bool(ClassT::*_callback)(const RequestT &_request, ReplyT &_reply), - ClassT *_obj, - const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); - - /// \brief Advertise a new service without input parameter. - /// In this version the callback is a member function. - /// \param[in] _topic Topic name associated to the service. - /// \param[in] _callback Callback to handle the service request with the - /// following parameters: - /// * _reply Protobuf message containing the response. - /// * Returns Service call result. - /// \param[in] _obj Instance containing the member function. - /// \param[in] _options Advertise options. - /// \return true when the topic has been successfully advertised or - /// false otherwise. - /// \sa AdvertiseOptions. - public: template - bool Advertise( - const std::string &_topic, - bool(ClassT::*_callback)(ReplyT &_reply), - ClassT *_obj, - const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); - - /// \brief Advertise a new service without any output parameter. - /// In this version the callback is a member function. - /// \param[in] _topic Topic name associated to the service. - /// \param[in] _callback Callback to handle the service request with the - /// following parameters: - /// * _request Protobuf message containing the request. - /// \param[in] _obj Instance containing the member function. - /// \param[in] _options Advertise options. - /// \return true when the topic has been successfully advertised or - /// false otherwise. - /// \sa AdvertiseOptions - public: template - bool Advertise( - const std::string &_topic, - void(ClassT::*_callback)(const RequestT &_request), - ClassT *_obj, - const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); - - /// \brief Get the list of services advertised by this node. - /// \return A vector containing all services advertised by this node. - public: std::vector AdvertisedServices() const; - - /// \brief Request a new service using a non-blocking call. - /// In this version the callback is a free function. - /// \param[in] _topic Service name requested. - /// \param[in] _request Protobuf message containing the request's - /// parameters. - /// \param[in] _callback Pointer to the callback function executed when - /// the response arrives. The callback has the following parameters: - /// * _reply Protobuf message containing the response. - /// * _result Result of the service call. If false, there was - /// a problem executing your request. - /// \return true when the service call was succesfully requested. - public: template - bool Request( - const std::string &_topic, - const RequestT &_request, - void(*_callback)(const ReplyT &_reply, const bool _result)); - - /// \brief Request a new service without input parameter using a - /// non-blocking call. - /// In this version the callback is a free function. - /// \param[in] _topic Service name requested. - /// \param[in] _callback Pointer to the callback function executed when - /// the response arrives. The callback has the following parameters: - /// * _reply Protobuf message containing the response. - /// * _result Result of the service call. If false, there was - /// a problem executing your request. - /// \return true when the service call was succesfully requested. - public: template - bool Request( - const std::string &_topic, - void(*_callback)(const ReplyT &_reply, const bool _result)); - - /// \brief Request a new service using a non-blocking call. - /// In this version the callback is a lambda function. - /// \param[in] _topic Service name requested. - /// \param[in] _request Protobuf message containing the request's - /// parameters. - /// \param[in] _callback Lambda function executed when the response - /// arrives. The callback has the following parameters: - /// * _reply Protobuf message containing the response. - /// * _result Result of the service call. If false, there was - /// a problem executing your request. - /// \return true when the service call was succesfully requested. - public: template - bool Request( - const std::string &_topic, - const RequestT &_request, - std::function &_callback); - - /// \brief Request a new service without input parameter using a - /// non-blocking call. - /// In this version the callback is a lambda function. - /// \param[in] _topic Service name requested. - /// \param[in] _callback Lambda function executed when the response - /// arrives. The callback has the following parameters: - /// * _reply Protobuf message containing the response. - /// * _result Result of the service call. If false, there was - /// a problem executing your request. - /// \return true when the service call was succesfully requested. - public: template - bool Request( - const std::string &_topic, - std::function &_callback); - - /// \brief Request a new service using a non-blocking call. - /// In this version the callback is a member function. - /// \param[in] _topic Service name requested. - /// \param[in] _request Protobuf message containing the request's - /// parameters. - /// \param[in] _callback Pointer to the callback function executed when - /// the response arrives. The callback has the following parameters: - /// * _reply Protobuf message containing the response. - /// * _result Result of the service call. If false, there was - /// a problem executing your request. - /// \param[in] _obj Instance containing the member function. - /// \return true when the service call was succesfully requested. - public: template - bool Request( - const std::string &_topic, - const RequestT &_request, - void(ClassT::*_callback)(const ReplyT &_reply, const bool _result), - ClassT *_obj); - - /// \brief Request a new service without input parameter using a - /// non-blocking call. - /// In this version the callback is a member function. - /// \param[in] _topic Service name requested. - /// \param[in] _callback Pointer to the callback function executed when - /// the response arrives. The callback has the following parameters: - /// * _reply Protobuf message containing the response. - /// * _result Result of the service call. If false, there was - /// a problem executing your request. - /// \param[in] _obj Instance containing the member function. - /// \return true when the service call was succesfully requested. - public: template - bool Request( - const std::string &_topic, - void(ClassT::*_callback)(const ReplyT &_reply, const bool _result), - ClassT *_obj); - - /// \brief Request a new service using a blocking call. - /// \param[in] _topic Service name requested. - /// \param[in] _request Protobuf message containing the request's - /// parameters. - /// \param[in] _timeout The request will timeout after '_timeout' ms. - /// \param[out] _reply Protobuf message containing the response. - /// \param[out] _result Result of the service call. - /// \return true when the request was executed or false if the timeout - /// expired. - public: template - bool Request( - const std::string &_topic, - const RequestT &_request, - const unsigned int &_timeout, - ReplyT &_reply, - bool &_result); - - /// \brief Request a new service without input parameter using a blocking - /// call. - /// \param[in] _topic Service name requested. - /// \param[in] _timeout The request will timeout after '_timeout' ms. - /// \param[out] _reply Protobuf message containing the response. - /// \param[out] _result Result of the service call. - /// \return true when the request was executed or false if the timeout - /// expired. - public: template - bool Request( - const std::string &_topic, - const unsigned int &_timeout, - ReplyT &_reply, - bool &_result); - - /// \brief Request a new service without waiting for response. - /// \param[in] _topic Topic requested. - /// \param[in] _request Protobuf message containing the request's - /// parameters. - /// \return true when the service call was succesfully requested. - public: template - bool Request(const std::string &_topic, const RequestT &_request); - - /// \brief Request a new service using a blocking call. This request - /// function expects a serialized protobuf message as the request and - /// returns a serialized protobuf message as the response. - /// \param[in] _topic Service name requested. - /// \param[in] _request Protobuf message serialized into a string - /// containing the request's parameters. - /// \param[in] _requestType Message type of the request. - /// \param[in] _responseType Message type of the response. - /// \param[in] _timeout The request will timeout after '_timeout' ms. - /// \param[out] _response Serialized protobuf message containing the - /// response. - /// \param[out] _result Result of the service call. - /// \return true when the request was executed or false if the timeout - /// expired. - public: bool RequestRaw(const std::string &_topic, - const std::string &_request, const std::string &_requestType, - const std::string &_responseType, unsigned int _timeout, - std::string &_response, - bool &_result); - - /// \brief Unadvertise a service. - /// \param[in] _topic Service name to be unadvertised. - /// \return true if the service was successfully unadvertised. - public: bool UnadvertiseSrv(const std::string &_topic); - - /// \brief Get the list of topics currently advertised in the network. - /// Note that this function can block for some time if the - /// discovery is in its initialization phase. - /// The value of the "heartbeatInterval" constant, with a default - /// value of 1000 ms, sets the maximum blocking time period. - /// \param[out] _topics List of advertised topics. - public: void TopicList(std::vector &_topics) const; - - /// \brief Get the information about a topic. - /// \param[in] _topic Name of the topic. - /// \param[out] _publishers List of publishers on the topic - /// \return False if unable to get topic info - public: bool GZ_DEPRECATED(13) TopicInfo(const std::string &_topic, - std::vector &_publishers) const; - - /// \brief Get the information about a topic. - /// \param[in] _topic Name of the topic. - /// \param[out] _publishers List of publishers on the topic. - /// \param[out] _subscribers List of subscribers on the topic. - /// \return False if unable to get topic info. - public: bool TopicInfo(const std::string &_topic, - std::vector &_publishers, - std::vector &_subscribers) const; - - /// \brief Get the list of topics currently advertised in the network. - /// Note that this function can block for some time if the - /// discovery is in its initialization phase. - /// The value of the "heartbeatInterval" constant, with a default - /// value of 1000ms, sets the maximum blocking time period. - /// \param[out] _services List of advertised services. - public: void ServiceList(std::vector &_services) const; - - /// \brief Get the information about a service. - /// \param[in] _service Name of the service. - /// \param[out] _publishers List of publishers on the service. - /// \return False if unable to get service info. - public: bool ServiceInfo( - const std::string &_service, - std::vector &_publishers) const; - - /// \brief Subscribe to a topic registering a callback. The callback must - /// accept a std::string to represent the message data, and a MessageInfo - /// which provides metadata about the message. - /// \param[in] _topic Name of the topic to subscribe to - /// \param[in] _callback A function pointer or std::function object that - /// has a void return value and accepts two arguments: - /// (const std::string &_msgData, const MessageInfo &_info). - /// \param[in] _msgType The type of message to subscribe to. Using - /// kGenericMessageType (the default) will allow this subscriber to listen - /// to all message types. The callback function can identify the type for - /// each message by inspecting its const MessageInfo& input argument. - /// \param[in] _opts Options for subscribing. - /// \return True if subscribing was successful. - public: bool SubscribeRaw( + /// \brief Subscribe to a topic registering a callback. + /// Note that this callback includes message information. + /// In this version the callback is a free function. + /// \param[in] _topic Topic to be subscribed. + /// \param[in] _callback Pointer to the callback function with the + /// following parameters: + /// * _msg Protobuf message containing a new topic update. + /// * _info Message information (e.g.: topic name). + /// \param[in] _opts Subscription options. + /// \return true when successfully subscribed or false otherwise. + public: template + bool Subscribe( + const std::string &_topic, + void(*_callback)(const MessageT &_msg, const MessageInfo &_info), + const SubscribeOptions &_opts = SubscribeOptions()); + + /// \brief Subscribe to a topic registering a callback. + /// Note that this callback includes message information. + /// In this version the callback is a lamda function. + /// \param[in] _topic Topic to be subscribed. + /// \param[in] _callback Lambda function with the following parameters: + /// * _msg Protobuf message containing a new topic update. + /// * _info Message information (e.g.: topic name). + /// \param[in] _opts Subscription options. + /// \return true when successfully subscribed or false otherwise. + public: template + bool Subscribe( const std::string &_topic, - const RawCallback &_callback, - const std::string &_msgType = kGenericMessageType, + std::function _callback, const SubscribeOptions &_opts = SubscribeOptions()); - /// \brief Get the reference to the current node options. - /// \return Reference to the current node options. - public: const NodeOptions &Options() const; - - /// \brief Turn topic statistics on or off. - /// \param[in] _topic The name of the topic on which to enable or disable - /// statistics. - /// \param[in] _enable True to enable statistics, false to disable. - /// \param[in] _publicationTopic Topic on which to publish statistics. - /// \param[in] _publicationRate Rate at which to publish statistics. - public: bool EnableStats(const std::string &_topic, bool _enable, - const std::string &_publicationTopic = "/statistics", - uint64_t _publicationRate = 1); - - /// \brief Get the current statistics for a topic. Statistics must - /// have been enabled using the EnableStatistics function, otherwise - /// the return value will be std::nullopt. - /// \param[in] _topic The name of the topic to get statistics for. - /// return A TopicStatistics class, or std::nullopt if statistics were - /// not enabled. - public: std::optional TopicStats( - const std::string &_topic) const; - - /// \brief Get a pointer to the shared node (singleton shared by all the - /// nodes). - /// \return The pointer to the shared node. - private: NodeShared *Shared() const; - - /// \brief Get the UUID of this node. - /// \return The node UUID. - private: const std::string &NodeUuid() const; - - /// \brief Get the set of topics subscribed by this node. - /// \return The set of subscribed topics. - private: std::unordered_set &TopicsSubscribed() const; - - /// \brief Get the set of services advertised by this node. - /// \return The set of advertised services. - private: std::unordered_set &SrvsAdvertised() const; - - /// \brief Helper function for Subscribe. - /// \param[in] _fullyQualifiedTopic Fully qualified topic name - /// \return True on success. - private: bool SubscribeHelper(const std::string &_fullyQualifiedTopic); + /// \brief Subscribe to a topic registering a callback. + /// Note that this callback includes message information. + /// In this version the callback is a member function. + /// \param[in] _topic Topic to be subscribed. + /// \param[in] _callback Pointer to the callback function with the + /// following parameters: + /// * _msg Protobuf message containing a new topic update. + /// * _info Message information (e.g.: topic name). + /// \param[in] _obj Instance containing the member function. + /// \param[in] _opts Subscription options. + /// \return true when successfully subscribed or false otherwise. + public: template + bool Subscribe( + const std::string &_topic, + void(ClassT::*_callback)(const MessageT &_msg, + const MessageInfo &_info), + ClassT *_obj, + const SubscribeOptions &_opts = SubscribeOptions()); + + /// \brief Get the list of topics subscribed by this node. Note that + /// we might be interested in one topic but we still don't know the + /// address of a publisher. + /// \return A vector containing the subscribed topics (even if we do not + /// have an address for a particular topic yet). + public: std::vector SubscribedTopics() const; + + /// \brief Unsubscribe from a topic. + /// \param[in] _topic Topic name to be unsubscribed. + /// \return true when successfully unsubscribed or false otherwise. + public: bool Unsubscribe(const std::string &_topic); + + /// \brief Advertise a new service. + /// In this version the callback is a plain function pointer. + /// \param[in] _topic Topic name associated to the service. + /// \param[in] _callback Callback to handle the service request with the + /// following parameters: + /// * _request Protobuf message containing the request. + /// * _reply Protobuf message containing the response. + /// * Returns Service call result. + /// \param[in] _options Advertise options. + /// \return true when the topic has been successfully advertised or + /// false otherwise. + /// \sa AdvertiseOptions. + public: template + bool Advertise( + const std::string &_topic, + bool(*_callback)(const RequestT &_request, ReplyT &_reply), + const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); + + /// \brief Advertise a new service without input parameter. + /// In this version the callback is a free function. + /// \param[in] _topic Topic name associated to the service. + /// \param[in] _callback Callback to handle the service request with the + /// following parameters: + /// * _reply Protobuf message containing the response. + /// * Returns Service call result. + /// \param[in] _options Advertise options. + /// \return true when the topic has been successfully advertised or + /// false otherwise. + /// \sa AdvertiseOptions. + public: template + bool Advertise( + const std::string &_topic, + bool(*_callback)(ReplyT &_reply), + const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); + + /// \brief Advertise a new service without any output parameter. + /// In this version the callback is a free function. + /// \param[in] _topic Topic name associated to the service. + /// \param[in] _callback Callback to handle the service request with the + /// following parameters: + /// * _request Protobuf message containing the request. + /// \param[in] _options Advertise options. + /// \return true when the topic has been successfully advertised or + /// false otherwise. + /// \sa AdvertiseOptions. + public: template + bool Advertise( + const std::string &_topic, + void(*_callback)(const RequestT &_request), + const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); + + /// \brief Advertise a new service. + /// In this version the callback is a lambda function. + /// \param[in] _topic Topic name associated to the service. + /// \param[in] _callback Callback to handle the service request with the + /// following parameters: + /// * _request Protobuf message containing the request. + /// * _reply Protobuf message containing the response. + /// * Returns Service call result. + /// \param[in] _options Advertise options. + /// \return true when the topic has been successfully advertised or + /// false otherwise. + /// \sa AdvertiseOptions. + public: template + bool Advertise( + const std::string &_topic, + std::function _callback, + const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); + + /// \brief Advertise a new service without input parameter. + /// In this version the callback is a lambda function. + /// \param[in] _topic Topic name associated to the service. + /// \param[in] _callback Callback to handle the service request with the + /// following parameters: + /// * _reply Protobuf message containing the response. + /// * Returns Service call result. + /// \param[in] _options Advertise options. + /// \return true when the topic has been successfully advertised or + /// false otherwise. + /// \sa AdvertiseOptions. + public: template + bool Advertise( + const std::string &_topic, + std::function &_callback, + const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); + + /// \brief Advertise a new service without any output parameter. + /// In this version the callback is a lambda function. + /// \param[in] _topic Topic name associated to the service. + /// \param[in] _callback Callback to handle the service request with the + /// following parameters: + /// * _request Protobuf message containing the request. + /// \param[in] _options Advertise options. + /// \return true when the topic has been successfully advertised or + /// false otherwise. + /// \sa AdvertiseOptions. + public: template + bool Advertise( + const std::string &_topic, + std::function &_callback, + const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); + + /// \brief Advertise a new service. + /// In this version the callback is a member function. + /// \param[in] _topic Topic name associated to the service. + /// \param[in] _callback Callback to handle the service request with the + /// following parameters: + /// * _request Protobuf message containing the request. + /// * _reply Protobuf message containing the response. + /// * Returns Service call result. + /// \param[in] _obj Instance containing the member function. + /// \param[in] _options Advertise options. + /// \return true when the topic has been successfully advertised or + /// false otherwise. + /// \sa AdvertiseOptions. + public: template + bool Advertise( + const std::string &_topic, + bool(ClassT::*_callback)(const RequestT &_request, ReplyT &_reply), + ClassT *_obj, + const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); + + /// \brief Advertise a new service without input parameter. + /// In this version the callback is a member function. + /// \param[in] _topic Topic name associated to the service. + /// \param[in] _callback Callback to handle the service request with the + /// following parameters: + /// * _reply Protobuf message containing the response. + /// * Returns Service call result. + /// \param[in] _obj Instance containing the member function. + /// \param[in] _options Advertise options. + /// \return true when the topic has been successfully advertised or + /// false otherwise. + /// \sa AdvertiseOptions. + public: template + bool Advertise( + const std::string &_topic, + bool(ClassT::*_callback)(ReplyT &_reply), + ClassT *_obj, + const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); + + /// \brief Advertise a new service without any output parameter. + /// In this version the callback is a member function. + /// \param[in] _topic Topic name associated to the service. + /// \param[in] _callback Callback to handle the service request with the + /// following parameters: + /// * _request Protobuf message containing the request. + /// \param[in] _obj Instance containing the member function. + /// \param[in] _options Advertise options. + /// \return true when the topic has been successfully advertised or + /// false otherwise. + /// \sa AdvertiseOptions + public: template + bool Advertise( + const std::string &_topic, + void(ClassT::*_callback)(const RequestT &_request), + ClassT *_obj, + const AdvertiseServiceOptions &_options = AdvertiseServiceOptions()); + + /// \brief Get the list of services advertised by this node. + /// \return A vector containing all services advertised by this node. + public: std::vector AdvertisedServices() const; + + /// \brief Request a new service using a non-blocking call. + /// In this version the callback is a free function. + /// \param[in] _topic Service name requested. + /// \param[in] _request Protobuf message containing the request's + /// parameters. + /// \param[in] _callback Pointer to the callback function executed when + /// the response arrives. The callback has the following parameters: + /// * _reply Protobuf message containing the response. + /// * _result Result of the service call. If false, there was + /// a problem executing your request. + /// \return true when the service call was succesfully requested. + public: template + bool Request( + const std::string &_topic, + const RequestT &_request, + void(*_callback)(const ReplyT &_reply, const bool _result)); + + /// \brief Request a new service without input parameter using a + /// non-blocking call. + /// In this version the callback is a free function. + /// \param[in] _topic Service name requested. + /// \param[in] _callback Pointer to the callback function executed when + /// the response arrives. The callback has the following parameters: + /// * _reply Protobuf message containing the response. + /// * _result Result of the service call. If false, there was + /// a problem executing your request. + /// \return true when the service call was succesfully requested. + public: template + bool Request( + const std::string &_topic, + void(*_callback)(const ReplyT &_reply, const bool _result)); + + /// \brief Request a new service using a non-blocking call. + /// In this version the callback is a lambda function. + /// \param[in] _topic Service name requested. + /// \param[in] _request Protobuf message containing the request's + /// parameters. + /// \param[in] _callback Lambda function executed when the response + /// arrives. The callback has the following parameters: + /// * _reply Protobuf message containing the response. + /// * _result Result of the service call. If false, there was + /// a problem executing your request. + /// \return true when the service call was succesfully requested. + public: template + bool Request( + const std::string &_topic, + const RequestT &_request, + std::function &_callback); + + /// \brief Request a new service without input parameter using a + /// non-blocking call. + /// In this version the callback is a lambda function. + /// \param[in] _topic Service name requested. + /// \param[in] _callback Lambda function executed when the response + /// arrives. The callback has the following parameters: + /// * _reply Protobuf message containing the response. + /// * _result Result of the service call. If false, there was + /// a problem executing your request. + /// \return true when the service call was succesfully requested. + public: template + bool Request( + const std::string &_topic, + std::function &_callback); + + /// \brief Request a new service using a non-blocking call. + /// In this version the callback is a member function. + /// \param[in] _topic Service name requested. + /// \param[in] _request Protobuf message containing the request's + /// parameters. + /// \param[in] _callback Pointer to the callback function executed when + /// the response arrives. The callback has the following parameters: + /// * _reply Protobuf message containing the response. + /// * _result Result of the service call. If false, there was + /// a problem executing your request. + /// \param[in] _obj Instance containing the member function. + /// \return true when the service call was succesfully requested. + public: template + bool Request( + const std::string &_topic, + const RequestT &_request, + void(ClassT::*_callback)(const ReplyT &_reply, const bool _result), + ClassT *_obj); + + /// \brief Request a new service without input parameter using a + /// non-blocking call. + /// In this version the callback is a member function. + /// \param[in] _topic Service name requested. + /// \param[in] _callback Pointer to the callback function executed when + /// the response arrives. The callback has the following parameters: + /// * _reply Protobuf message containing the response. + /// * _result Result of the service call. If false, there was + /// a problem executing your request. + /// \param[in] _obj Instance containing the member function. + /// \return true when the service call was succesfully requested. + public: template + bool Request( + const std::string &_topic, + void(ClassT::*_callback)(const ReplyT &_reply, const bool _result), + ClassT *_obj); + + /// \brief Request a new service using a blocking call. + /// \param[in] _topic Service name requested. + /// \param[in] _request Protobuf message containing the request's + /// parameters. + /// \param[in] _timeout The request will timeout after '_timeout' ms. + /// \param[out] _reply Protobuf message containing the response. + /// \param[out] _result Result of the service call. + /// \return true when the request was executed or false if the timeout + /// expired. + public: template + bool Request( + const std::string &_topic, + const RequestT &_request, + const unsigned int &_timeout, + ReplyT &_reply, + bool &_result); + + /// \brief Request a new service without input parameter using a blocking + /// call. + /// \param[in] _topic Service name requested. + /// \param[in] _timeout The request will timeout after '_timeout' ms. + /// \param[out] _reply Protobuf message containing the response. + /// \param[out] _result Result of the service call. + /// \return true when the request was executed or false if the timeout + /// expired. + public: template + bool Request( + const std::string &_topic, + const unsigned int &_timeout, + ReplyT &_reply, + bool &_result); + + /// \brief Request a new service without waiting for response. + /// \param[in] _topic Topic requested. + /// \param[in] _request Protobuf message containing the request's + /// parameters. + /// \return true when the service call was succesfully requested. + public: template + bool Request(const std::string &_topic, const RequestT &_request); + + /// \brief Request a new service using a blocking call. This request + /// function expects a serialized protobuf message as the request and + /// returns a serialized protobuf message as the response. + /// \param[in] _topic Service name requested. + /// \param[in] _request Protobuf message serialized into a string + /// containing the request's parameters. + /// \param[in] _requestType Message type of the request. + /// \param[in] _responseType Message type of the response. + /// \param[in] _timeout The request will timeout after '_timeout' ms. + /// \param[out] _response Serialized protobuf message containing the + /// response. + /// \param[out] _result Result of the service call. + /// \return true when the request was executed or false if the timeout + /// expired. + public: bool RequestRaw(const std::string &_topic, + const std::string &_request, const std::string &_requestType, + const std::string &_responseType, unsigned int _timeout, + std::string &_response, + bool &_result); + + /// \brief Unadvertise a service. + /// \param[in] _topic Service name to be unadvertised. + /// \return true if the service was successfully unadvertised. + public: bool UnadvertiseSrv(const std::string &_topic); + + /// \brief Get the list of topics currently advertised in the network. + /// Note that this function can block for some time if the + /// discovery is in its initialization phase. + /// The value of the "heartbeatInterval" constant, with a default + /// value of 1000 ms, sets the maximum blocking time period. + /// \param[out] _topics List of advertised topics. + public: void TopicList(std::vector &_topics) const; + + /// \brief Get the information about a topic. + /// \param[in] _topic Name of the topic. + /// \param[out] _publishers List of publishers on the topic + /// \return False if unable to get topic info + public: bool GZ_DEPRECATED(13) TopicInfo(const std::string &_topic, + std::vector &_publishers) const; + + /// \brief Get the information about a topic. + /// \param[in] _topic Name of the topic. + /// \param[out] _publishers List of publishers on the topic. + /// \param[out] _subscribers List of subscribers on the topic. + /// \return False if unable to get topic info. + public: bool TopicInfo(const std::string &_topic, + std::vector &_publishers, + std::vector &_subscribers) const; + + /// \brief Get the list of topics currently advertised in the network. + /// Note that this function can block for some time if the + /// discovery is in its initialization phase. + /// The value of the "heartbeatInterval" constant, with a default + /// value of 1000ms, sets the maximum blocking time period. + /// \param[out] _services List of advertised services. + public: void ServiceList(std::vector &_services) const; + + /// \brief Get the information about a service. + /// \param[in] _service Name of the service. + /// \param[out] _publishers List of publishers on the service. + /// \return False if unable to get service info. + public: bool ServiceInfo( + const std::string &_service, + std::vector &_publishers) const; + + /// \brief Subscribe to a topic registering a callback. The callback must + /// accept a std::string to represent the message data, and a MessageInfo + /// which provides metadata about the message. + /// \param[in] _topic Name of the topic to subscribe to + /// \param[in] _callback A function pointer or std::function object that + /// has a void return value and accepts two arguments: + /// (const std::string &_msgData, const MessageInfo &_info). + /// \param[in] _msgType The type of message to subscribe to. Using + /// kGenericMessageType (the default) will allow this subscriber to listen + /// to all message types. The callback function can identify the type for + /// each message by inspecting its const MessageInfo& input argument. + /// \param[in] _opts Options for subscribing. + /// \return True if subscribing was successful. + public: bool SubscribeRaw( + const std::string &_topic, + const RawCallback &_callback, + const std::string &_msgType = kGenericMessageType, + const SubscribeOptions &_opts = SubscribeOptions()); + + /// \brief Get the reference to the current node options. + /// \return Reference to the current node options. + public: const NodeOptions &Options() const; + + /// \brief Turn topic statistics on or off. + /// \param[in] _topic The name of the topic on which to enable or disable + /// statistics. + /// \param[in] _enable True to enable statistics, false to disable. + /// \param[in] _publicationTopic Topic on which to publish statistics. + /// \param[in] _publicationRate Rate at which to publish statistics. + public: bool EnableStats(const std::string &_topic, bool _enable, + const std::string &_publicationTopic = "/statistics", + uint64_t _publicationRate = 1); + + /// \brief Get the current statistics for a topic. Statistics must + /// have been enabled using the EnableStatistics function, otherwise + /// the return value will be std::nullopt. + /// \param[in] _topic The name of the topic to get statistics for. + /// return A TopicStatistics class, or std::nullopt if statistics were + /// not enabled. + public: std::optional TopicStats( + const std::string &_topic) const; + + /// \brief Get a pointer to the shared node (singleton shared by all the + /// nodes). + /// \return The pointer to the shared node. + private: NodeShared *Shared() const; + + /// \brief Get the UUID of this node. + /// \return The node UUID. + private: const std::string &NodeUuid() const; + + /// \brief Get the set of topics subscribed by this node. + /// \return The set of subscribed topics. + private: std::unordered_set &TopicsSubscribed() const; + + /// \brief Get the set of services advertised by this node. + /// \return The set of advertised services. + private: std::unordered_set &SrvsAdvertised() const; + + /// \brief Helper function for Subscribe. + /// \param[in] _fullyQualifiedTopic Fully qualified topic name + /// \return True on success. + private: bool SubscribeHelper(const std::string &_fullyQualifiedTopic); #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -790,17 +788,14 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal - /// \brief Smart pointer to private data. - private: std::unique_ptr dataPtr; + /// \internal + /// \brief Smart pointer to private data. + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } -} - + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport #include "gz/transport/detail/Node.hh" - -#endif +#endif // GZ_TRANSPORT_NODE_HH_ diff --git a/include/gz/transport/NodeOptions.hh b/include/gz/transport/NodeOptions.hh index 409b62e97..d261ac494 100644 --- a/include/gz/transport/NodeOptions.hh +++ b/include/gz/transport/NodeOptions.hh @@ -24,107 +24,105 @@ #include "gz/transport/config.hh" #include "gz/transport/Export.hh" -namespace gz +namespace gz::transport { - namespace transport - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - // Forward declarations. - class NodeOptionsPrivate; + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + // Forward declarations. + class NodeOptionsPrivate; - /// \class NodeOptions NodeOptions.hh gz/transport/NodeOptions.hh - /// \brief A class for customizing the behavior of the Node. - /// E.g.: Set a custom namespace or a partition name. - class GZ_TRANSPORT_VISIBLE NodeOptions - { - /// \brief Constructor. - public: NodeOptions(); + /// \class NodeOptions NodeOptions.hh gz/transport/NodeOptions.hh + /// \brief A class for customizing the behavior of the Node. + /// E.g.: Set a custom namespace or a partition name. + class GZ_TRANSPORT_VISIBLE NodeOptions + { + /// \brief Constructor. + public: NodeOptions(); - /// \brief Copy constructor. - /// \param[in] _other NodeOptions to copy. - public: NodeOptions(const NodeOptions &_other); + /// \brief Copy constructor. + /// \param[in] _other NodeOptions to copy. + public: NodeOptions(const NodeOptions &_other); - /// \brief Destructor. - public: virtual ~NodeOptions(); + /// \brief Destructor. + public: virtual ~NodeOptions(); - /// \brief Assignment operator. - /// \param[in] _other The new NodeOptions. - /// \return A reference to this instance. - public: NodeOptions &operator=(const NodeOptions &_other); + /// \brief Assignment operator. + /// \param[in] _other The new NodeOptions. + /// \return A reference to this instance. + public: NodeOptions &operator=(const NodeOptions &_other); - /// \brief Get the namespace used in this node. - /// \return The namespace. - /// \sa SetNameSpace. - public: const std::string &NameSpace() const; + /// \brief Get the namespace used in this node. + /// \return The namespace. + /// \sa SetNameSpace. + public: const std::string &NameSpace() const; - /// \brief Set the node's namespace. A namespace is considered a prefix - /// that might be potentially applied to some of the topic/services - /// advertised in a node. - /// E.g.: Node1 sets a namespace 'ns1' and advertises the topics - /// 't1', 't2' and '/t3'. '/t3' is considered an absolute topic (starts - /// with '/') and it won't be affected by a namespace. However, 't1' and - /// 't2' will be advertised as '/ns1/t1' and '/ns1/t2'. - /// A namespace is any alphanumeric string with a few exceptions. - /// The symbol '/' is allowed as part of a namespace but just '/' is not - /// allowed. The symbols '@', '~' and ' ' are not allowed as part of a - /// namespace. Two or more consecutive slashes ('//') are not allowed. - /// \param[in] _ns The namespace. - /// \return True when operation succeed or false if the namespace was - /// invalid. - /// \sa NameSpace. - public: bool SetNameSpace(const std::string &_ns); + /// \brief Set the node's namespace. A namespace is considered a prefix + /// that might be potentially applied to some of the topic/services + /// advertised in a node. + /// E.g.: Node1 sets a namespace 'ns1' and advertises the topics + /// 't1', 't2' and '/t3'. '/t3' is considered an absolute topic (starts + /// with '/') and it won't be affected by a namespace. However, 't1' and + /// 't2' will be advertised as '/ns1/t1' and '/ns1/t2'. + /// A namespace is any alphanumeric string with a few exceptions. + /// The symbol '/' is allowed as part of a namespace but just '/' is not + /// allowed. The symbols '@', '~' and ' ' are not allowed as part of a + /// namespace. Two or more consecutive slashes ('//') are not allowed. + /// \param[in] _ns The namespace. + /// \return True when operation succeed or false if the namespace was + /// invalid. + /// \sa NameSpace. + public: bool SetNameSpace(const std::string &_ns); - /// \brief Get the partition used in this node. - /// \return The partition name. - /// \sa SetPartition. - public: const std::string &Partition() const; + /// \brief Get the partition used in this node. + /// \return The partition name. + /// \sa SetPartition. + public: const std::string &Partition() const; - /// \brief Set the node's partition name. A partition is used to - /// isolate a set of topics or services from other nodes that use the same - /// names. E.g.: Node1 advertises topics '/foo' and Node2 advertises - /// '/foo' too. If we don't use a partition, a node subscribed to '/foo' - /// will receive the messages published from Node1 and Node2. - /// Alternatively, we could specify 'p1' as a partition for Node1 and 'p2' - /// as a partition for Node2. When we create the node for our subscriber, - /// if we specify 'p1' as a partition name, we'll receive the messages - /// published only by Node1. If we use 'p2', we'll only receive the - /// messages published by Node2. If we don't set a partition name, we - /// won't receive any messages from Node1 or Node2. - /// A partition name is any alphanumeric string with a few exceptions. - /// The symbol '/' is allowed as part of a partition name but just '/' is - /// not allowed. The symbols '@', '~' and ' ' are not allowed as part of a - /// partition name. Two or more consecutive slashes ('//') are not allowed - /// \param[in] _partition The partition's name. - /// The default partition value is created using a combination of your - /// hostname, followed by ':' and your username. E.g.: "bb9:caguero" . - /// It's also possible to use the environment variable GZ_PARTITION for - /// setting a partition name. - /// \return True when operation succeed or false if the partition name was - /// invalid. - /// \sa Partition - public: bool SetPartition(const std::string &_partition); + /// \brief Set the node's partition name. A partition is used to + /// isolate a set of topics or services from other nodes that use the same + /// names. E.g.: Node1 advertises topics '/foo' and Node2 advertises + /// '/foo' too. If we don't use a partition, a node subscribed to '/foo' + /// will receive the messages published from Node1 and Node2. + /// Alternatively, we could specify 'p1' as a partition for Node1 and 'p2' + /// as a partition for Node2. When we create the node for our subscriber, + /// if we specify 'p1' as a partition name, we'll receive the messages + /// published only by Node1. If we use 'p2', we'll only receive the + /// messages published by Node2. If we don't set a partition name, we + /// won't receive any messages from Node1 or Node2. + /// A partition name is any alphanumeric string with a few exceptions. + /// The symbol '/' is allowed as part of a partition name but just '/' is + /// not allowed. The symbols '@', '~' and ' ' are not allowed as part of a + /// partition name. Two or more consecutive slashes ('//') are not allowed + /// \param[in] _partition The partition's name. + /// The default partition value is created using a combination of your + /// hostname, followed by ':' and your username. E.g.: "bb9:caguero" . + /// It's also possible to use the environment variable GZ_PARTITION for + /// setting a partition name. + /// \return True when operation succeed or false if the partition name was + /// invalid. + /// \sa Partition + public: bool SetPartition(const std::string &_partition); - /// \brief Add a new topic remapping. Any [Un]Advertise(), - /// [Un]Subscribe() or Request() operation will check for topic - /// remappings. If a topic is remapped, the '_fromTopic' topic will be - /// renamed to '_toTopic' in any of the previous functions. - /// Is not possible to add two remaps over the same '_fromTopic'. - /// \param[in] _fromTopic Original topic to be renamed. - /// \param[in] _toTopic New topic to be used. - /// \return True if the topic remap is possible or false otherwise. - public: bool AddTopicRemap(const std::string &_fromTopic, - const std::string &_toTopic); + /// \brief Add a new topic remapping. Any [Un]Advertise(), + /// [Un]Subscribe() or Request() operation will check for topic + /// remappings. If a topic is remapped, the '_fromTopic' topic will be + /// renamed to '_toTopic' in any of the previous functions. + /// Is not possible to add two remaps over the same '_fromTopic'. + /// \param[in] _fromTopic Original topic to be renamed. + /// \param[in] _toTopic New topic to be used. + /// \return True if the topic remap is possible or false otherwise. + public: bool AddTopicRemap(const std::string &_fromTopic, + const std::string &_toTopic); - /// \brief Get a topic remapping. - /// \param[in] _fromTopic The original topic. - /// \param[out] _toTopic The new topic name. - /// _toTopic is unchanged if there is no remapping. - /// \return True if a topic remap was found for '_fromTopic' or - /// false otherwise. - public: bool TopicRemap(const std::string &_fromTopic, - std::string &_toTopic) const; + /// \brief Get a topic remapping. + /// \param[in] _fromTopic The original topic. + /// \param[out] _toTopic The new topic name. + /// _toTopic is unchanged if there is no remapping. + /// \return True if a topic remap was found for '_fromTopic' or + /// false otherwise. + public: bool TopicRemap(const std::string &_fromTopic, + std::string &_toTopic) const; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -132,14 +130,13 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal - /// \brief Smart pointer to private data. - protected: std::unique_ptr dataPtr; + /// \internal + /// \brief Smart pointer to private data. + protected: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } -} -#endif + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_NODEOPTIONS_HH_ diff --git a/include/gz/transport/NodeShared.hh b/include/gz/transport/NodeShared.hh index 56df051dc..93abaef37 100644 --- a/include/gz/transport/NodeShared.hh +++ b/include/gz/transport/NodeShared.hh @@ -47,263 +47,261 @@ #include "gz/transport/TransportTypes.hh" #include "gz/transport/Uuid.hh" -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + // Forward declarations. + class Node; + class NodePrivate; + + /// \brief Private data pointer + class NodeSharedPrivate; + + /// \class NodeShared NodeShared.hh gz/transport/NodeShared.hh + /// \brief Private data for the Node class. This class should not be + /// directly used. You should use the Node class. + class GZ_TRANSPORT_VISIBLE NodeShared { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - // Forward declarations. - class Node; - class NodePrivate; - - /// \brief Private data pointer - class NodeSharedPrivate; - - /// \class NodeShared NodeShared.hh gz/transport/NodeShared.hh - /// \brief Private data for the Node class. This class should not be - /// directly used. You should use the Node class. - class GZ_TRANSPORT_VISIBLE NodeShared + /// \brief NodeShared is a singleton. This method gets the + /// NodeShared instance shared between all the nodes. + /// \return Pointer to the current NodeShared instance. + public: static NodeShared *Instance(); + + /// \brief Receive data and control messages. + public: void RunReceptionTask(); + + /// \brief Publish data. + /// \param[in] _topic Topic to be published. + /// \param[in, out] _data Serialized data. Note that this buffer will be + /// automatically deallocated by ZMQ when all data has been published. + /// \param[in] _dataSize Data size (bytes). + /// \param[in, out] _ffn Deallocation function. This function is + /// executed by ZeroMQ when the data is published. This function + /// deallocates the buffer containing the published data. + /// \sa http://zeromq.org/blog:zero-copy + /// \param[in] _msgType Message type in string format. + /// \return true when success or false otherwise. + public: bool Publish(const std::string &_topic, + char *_data, + const size_t _dataSize, + DeallocFunc *_ffn, + const std::string &_msgType); + + /// \brief Method in charge of receiving the topic updates. + public: void RecvMsgUpdate(); + + /// \brief HandlerInfo contains information about callback handlers which + /// is useful for local publishers and message receivers. You should only + /// retrieve a HandlerInfo by calling + /// CheckHandlerInfo(const std::string &_topic) const + public: struct HandlerInfo { - /// \brief NodeShared is a singleton. This method gets the - /// NodeShared instance shared between all the nodes. - /// \return Pointer to the current NodeShared instance. - public: static NodeShared *Instance(); - - /// \brief Receive data and control messages. - public: void RunReceptionTask(); - - /// \brief Publish data. - /// \param[in] _topic Topic to be published. - /// \param[in, out] _data Serialized data. Note that this buffer will be - /// automatically deallocated by ZMQ when all data has been published. - /// \param[in] _dataSize Data size (bytes). - /// \param[in, out] _ffn Deallocation function. This function is - /// executed by ZeroMQ when the data is published. This function - /// deallocates the buffer containing the published data. - /// \sa http://zeromq.org/blog:zero-copy - /// \param[in] _msgType Message type in string format. - /// \return true when success or false otherwise. - public: bool Publish(const std::string &_topic, - char *_data, - const size_t _dataSize, - DeallocFunc *_ffn, - const std::string &_msgType); - - /// \brief Method in charge of receiving the topic updates. - public: void RecvMsgUpdate(); - - /// \brief HandlerInfo contains information about callback handlers which - /// is useful for local publishers and message receivers. You should only - /// retrieve a HandlerInfo by calling - /// CheckHandlerInfo(const std::string &_topic) const - public: struct HandlerInfo - { - /// \brief This is a map of the standard local callback handlers. The - /// key is the topic name, and the value is another map whose key is - /// the node UUID and whose value is a smart pointer to the handler. - public: std::map localHandlers; - - /// \brief This is a map of the raw local callback handlers. The key is - /// the topic name, and the value is another map whose key is the node - /// UUID and whose value is a smart pointer to the handler. - public: std::map rawHandlers; - - /// \brief True iff there are any standard local subscribers. - public: bool haveLocal; - - /// \brief True iff there are any raw local subscribers - public: bool haveRaw; - - // Friendship. This allows HandlerInfo to be created by - // CheckHandlerInfo() - friend class NodeShared; - - // TODO(sloretz) private default constructor (visual studio 2017?) - }; - - /// \brief Get information about the local and raw subscribers that are - /// attached to this NodeShared. - /// \param[in] _topic Information will only be returned for handlers that - /// are subscribed to the given topic name. - /// \return Information about local subscription handlers that are held by - /// this NodeShared. - HandlerInfo CheckHandlerInfo(const std::string &_topic) const; - - /// \brief This struct provides information about the Subscribers of a - /// Publisher. It should only be retrieved using - /// CheckSubscriberInfo(const std::string&, const std::string&) const. - /// The relevant subscriber info is a superset of the relevant HandlerInfo - /// so we extend that struct. - /// - /// This struct is used internally by publishers to determine what kind of - /// subscribers they have. - public: struct SubscriberInfo : public HandlerInfo - { - /// \brief True if this Publisher has any remote subscribers - // cppcheck-suppress unusedStructMember - public: bool haveRemote; - - // Friendship declaration - friend class NodeShared; - - // TODO(sloretz) private default constructor (visual studio 2017?) - }; - - /// \brief Get information about the nodes that are subscribed to the - /// publishers of this NodeShared. - /// \param[in] _topic Only information about subscribers to this topic - /// will be returned. - /// \param[in] _msgType If there are no remote subscribers listening for - /// this message type, then SubscriberInfo::haveRemote will be false in - /// the return value of this function. - /// \return Information about subscribers. - SubscriberInfo CheckSubscriberInfo( - const std::string &_topic, - const std::string &_msgType) const; + /// \brief This is a map of the standard local callback handlers. The + /// key is the topic name, and the value is another map whose key is + /// the node UUID and whose value is a smart pointer to the handler. + public: std::map localHandlers; + + /// \brief This is a map of the raw local callback handlers. The key is + /// the topic name, and the value is another map whose key is the node + /// UUID and whose value is a smart pointer to the handler. + public: std::map rawHandlers; + + /// \brief True iff there are any standard local subscribers. + public: bool haveLocal; + + /// \brief True iff there are any raw local subscribers + public: bool haveRaw; + + // Friendship. This allows HandlerInfo to be created by + // CheckHandlerInfo() + friend class NodeShared; - /// \brief Call the SubscriptionHandler callbacks (local and raw) for this - /// NodeShared. - /// \param[in] _info Message information. - /// \param[in] _msgData The raw serialized data for the message - /// \param[in] _handlerInfo Information for the handlers of this node, - /// as generated by CheckHandlerInfo(const std::string&) const - public: void TriggerCallbacks( - const MessageInfo &_info, - const std::string &_msgData, - const HandlerInfo &_handlerInfo); - - /// \brief Method in charge of receiving the service call requests. - public: void RecvSrvRequest(); - - /// \brief Method in charge of receiving the service call responses. - public: void RecvSrvResponse(); - - /// \brief Try to send all the requests for a given service call and a - /// pair of request/response types. - /// \param[in] _topic Topic name. - /// \param[in] _reqType Type of the request in string format. - /// \param[in] _repType Type of the response in string format. - public: void SendPendingRemoteReqs(const std::string &_topic, - const std::string &_reqType, - const std::string &_repType); - - /// \brief Callback executed when the discovery detects new topics. - /// \param[in] _pub Information of the publisher in charge of the topic. - public: void OnNewConnection(const MessagePublisher &_pub); - - /// \brief Callback executed when the discovery detects disconnections. - /// \param[in] _pub Information of the publisher in charge of the topic. - public: void OnNewDisconnection(const MessagePublisher &_pub); - - /// \brief Callback executed when the discovery detects a new service call - /// \param[in] _pub Information of the publisher in charge of the service. - public: void OnNewSrvConnection(const ServicePublisher &_pub); - - /// \brief Callback executed when a service call is no longer available. - /// \param[in] _pub Information of the publisher in charge of the service. - public: void OnNewSrvDisconnection(const ServicePublisher &_pub); - - /// \brief Callback executed when a remote subscriber connects. - /// \param[in] _pub Information of the remote subscriber. - public: void OnNewRegistration(const MessagePublisher &_pub); - - /// \brief Callback executed when a remote subscriber unregisters. - /// \param[in] _pub Information of the remote subscriber. - public: void OnEndRegistration(const MessagePublisher &_pub); - - /// \brief Callback executed when a SUBSCRIBERS request is received. - public: void OnSubscribers(); - - /// \brief Pass through to bool Publishers(const std::string &_topic, - /// Addresses_M &_publishers) const - /// \param[in] _topic Service name. - /// \param[out] _publishers Collection of service publishers. - /// \return True if the service is found and - // there is at least one publisher. - /// \sa bool Publishers(const std::string &_topic, - /// Addresses_M &_publishers) const - public: bool TopicPublishers(const std::string &_topic, - SrvAddresses_M &_publishers) const; - - /// \brief Pass through to bool Discovery::Discover(const std::string - /// &_topic) const - /// \param[in] _topic Service name. - /// \return True if the method succeeded or false otherwise - /// (e.g. if the discovery has not been started). - /// \sa bool Discovery::Discover(const std::string &_topic) const - public: bool DiscoverService(const std::string &_topic) const; - - /// \brief Pass through to bool Advertise(const Pub &_publisher) - /// \param[in] _publisher Publisher's information to advertise. - /// \return True if the method succeed or false otherwise - /// (e.g. if the discovery has not been started). - /// \sa Pass through to bool Advertise(const Pub &_publisher) - public: bool AdvertisePublisher(const ServicePublisher &_publisher); - - /// \brief Get the capacity of the buffer (High Water Mark) - /// that stores incoming Gazebo Transport messages. Note that this is a - /// global queue shared by all subscribers within the same process. - /// \return The capacity of the buffer storing incoming messages (units - /// are messages). A value of 0 indicates an unlimited buffer and -1 - /// that the socket cannot be queried. The default buffer size is - /// contained in the #kDefaultRcvHwm variable. - /// If the buffer is set to unlimited, then your buffer will grow until - /// you run out of memory (and probably crash). - /// If your buffer reaches the maximum capacity data will be dropped. - public: int RcvHwm(); - - /// \brief Get the capacity of the buffer (High Water Mark) - /// that stores outgoing Gazebo Transport messages. Note that this is a - /// global queue shared by all publishers within the same process. - /// \return The capacity of the buffer storing outgoing messages (units - /// are messages). A value of 0 indicates an unlimited buffer and -1 - /// that the socket cannot be queried. The default buffer size is - /// contained in the #kDefaultSndHwm variable. - /// If the buffer is set to unlimited, then your buffer will grow until - /// you run out of memory (and probably crash). - /// If your buffer reaches the maximum capacity data will be dropped. - public: int SndHwm(); - - /// \brief Turn topic statistics on or off. - /// \param[in] _topic The name of the topic on which to enable or disable - /// statistics. - /// \param[in] _enable True to enable statistics, false to disable. - /// \param[in] _cb Callback that is triggered whenever statistics are - /// updated. - public: void EnableStats(const std::string &_topic, bool _enable, - std::function _cb); - - /// \brief Get the current statistics for a topic. Statistics must - /// have been enabled using the EnableStatistics function, otherwise - /// the return value will be std::nullopt. - /// \param[in] _topic The name of the topic to get statistics for. - /// \return A TopicStatistics class, or std::nullopt if statistics were - /// not enabled. - public: std::optional TopicStats( - const std::string &_topic) const; - - /// \brief Constructor. - protected: NodeShared(); - - /// \brief Destructor. - protected: virtual ~NodeShared(); - - /// \brief Initialize all sockets. - /// \return True when success or false otherwise. This function might - /// return false if any operation on a ZMQ socket triggered an exception. - private: bool InitializeSockets(); - - ////////////////////////////////////////////////// - /////// Declare here other member variables ////// - ////////////////////////////////////////////////// - - /// \brief Response receiver socket identity. - public: Uuid responseReceiverId; - - /// \brief Replier socket identity. - public: Uuid replierId; + // TODO(sloretz) private default constructor (visual studio 2017?) + }; + + /// \brief Get information about the local and raw subscribers that are + /// attached to this NodeShared. + /// \param[in] _topic Information will only be returned for handlers that + /// are subscribed to the given topic name. + /// \return Information about local subscription handlers that are held by + /// this NodeShared. + HandlerInfo CheckHandlerInfo(const std::string &_topic) const; + + /// \brief This struct provides information about the Subscribers of a + /// Publisher. It should only be retrieved using + /// CheckSubscriberInfo(const std::string&, const std::string&) const. + /// The relevant subscriber info is a superset of the relevant HandlerInfo + /// so we extend that struct. + /// + /// This struct is used internally by publishers to determine what kind of + /// subscribers they have. + public: struct SubscriberInfo : public HandlerInfo + { + /// \brief True if this Publisher has any remote subscribers + // cppcheck-suppress unusedStructMember + public: bool haveRemote; + + // Friendship declaration + friend class NodeShared; + + // TODO(sloretz) private default constructor (visual studio 2017?) + }; + + /// \brief Get information about the nodes that are subscribed to the + /// publishers of this NodeShared. + /// \param[in] _topic Only information about subscribers to this topic + /// will be returned. + /// \param[in] _msgType If there are no remote subscribers listening for + /// this message type, then SubscriberInfo::haveRemote will be false in + /// the return value of this function. + /// \return Information about subscribers. + SubscriberInfo CheckSubscriberInfo( + const std::string &_topic, + const std::string &_msgType) const; + + /// \brief Call the SubscriptionHandler callbacks (local and raw) for this + /// NodeShared. + /// \param[in] _info Message information. + /// \param[in] _msgData The raw serialized data for the message + /// \param[in] _handlerInfo Information for the handlers of this node, + /// as generated by CheckHandlerInfo(const std::string&) const + public: void TriggerCallbacks( + const MessageInfo &_info, + const std::string &_msgData, + const HandlerInfo &_handlerInfo); + + /// \brief Method in charge of receiving the service call requests. + public: void RecvSrvRequest(); + + /// \brief Method in charge of receiving the service call responses. + public: void RecvSrvResponse(); + + /// \brief Try to send all the requests for a given service call and a + /// pair of request/response types. + /// \param[in] _topic Topic name. + /// \param[in] _reqType Type of the request in string format. + /// \param[in] _repType Type of the response in string format. + public: void SendPendingRemoteReqs(const std::string &_topic, + const std::string &_reqType, + const std::string &_repType); + + /// \brief Callback executed when the discovery detects new topics. + /// \param[in] _pub Information of the publisher in charge of the topic. + public: void OnNewConnection(const MessagePublisher &_pub); + + /// \brief Callback executed when the discovery detects disconnections. + /// \param[in] _pub Information of the publisher in charge of the topic. + public: void OnNewDisconnection(const MessagePublisher &_pub); + + /// \brief Callback executed when the discovery detects a new service call + /// \param[in] _pub Information of the publisher in charge of the service. + public: void OnNewSrvConnection(const ServicePublisher &_pub); + + /// \brief Callback executed when a service call is no longer available. + /// \param[in] _pub Information of the publisher in charge of the service. + public: void OnNewSrvDisconnection(const ServicePublisher &_pub); + + /// \brief Callback executed when a remote subscriber connects. + /// \param[in] _pub Information of the remote subscriber. + public: void OnNewRegistration(const MessagePublisher &_pub); + + /// \brief Callback executed when a remote subscriber unregisters. + /// \param[in] _pub Information of the remote subscriber. + public: void OnEndRegistration(const MessagePublisher &_pub); + + /// \brief Callback executed when a SUBSCRIBERS request is received. + public: void OnSubscribers(); + + /// \brief Pass through to bool Publishers(const std::string &_topic, + /// Addresses_M &_publishers) const + /// \param[in] _topic Service name. + /// \param[out] _publishers Collection of service publishers. + /// \return True if the service is found and + // there is at least one publisher. + /// \sa bool Publishers(const std::string &_topic, + /// Addresses_M &_publishers) const + public: bool TopicPublishers(const std::string &_topic, + SrvAddresses_M &_publishers) const; + + /// \brief Pass through to bool Discovery::Discover(const std::string + /// &_topic) const + /// \param[in] _topic Service name. + /// \return True if the method succeeded or false otherwise + /// (e.g. if the discovery has not been started). + /// \sa bool Discovery::Discover(const std::string &_topic) const + public: bool DiscoverService(const std::string &_topic) const; + + /// \brief Pass through to bool Advertise(const Pub &_publisher) + /// \param[in] _publisher Publisher's information to advertise. + /// \return True if the method succeed or false otherwise + /// (e.g. if the discovery has not been started). + /// \sa Pass through to bool Advertise(const Pub &_publisher) + public: bool AdvertisePublisher(const ServicePublisher &_publisher); + + /// \brief Get the capacity of the buffer (High Water Mark) + /// that stores incoming Gazebo Transport messages. Note that this is a + /// global queue shared by all subscribers within the same process. + /// \return The capacity of the buffer storing incoming messages (units + /// are messages). A value of 0 indicates an unlimited buffer and -1 + /// that the socket cannot be queried. The default buffer size is + /// contained in the #kDefaultRcvHwm variable. + /// If the buffer is set to unlimited, then your buffer will grow until + /// you run out of memory (and probably crash). + /// If your buffer reaches the maximum capacity data will be dropped. + public: int RcvHwm(); + + /// \brief Get the capacity of the buffer (High Water Mark) + /// that stores outgoing Gazebo Transport messages. Note that this is a + /// global queue shared by all publishers within the same process. + /// \return The capacity of the buffer storing outgoing messages (units + /// are messages). A value of 0 indicates an unlimited buffer and -1 + /// that the socket cannot be queried. The default buffer size is + /// contained in the #kDefaultSndHwm variable. + /// If the buffer is set to unlimited, then your buffer will grow until + /// you run out of memory (and probably crash). + /// If your buffer reaches the maximum capacity data will be dropped. + public: int SndHwm(); + + /// \brief Turn topic statistics on or off. + /// \param[in] _topic The name of the topic on which to enable or disable + /// statistics. + /// \param[in] _enable True to enable statistics, false to disable. + /// \param[in] _cb Callback that is triggered whenever statistics are + /// updated. + public: void EnableStats(const std::string &_topic, bool _enable, + std::function _cb); + + /// \brief Get the current statistics for a topic. Statistics must + /// have been enabled using the EnableStatistics function, otherwise + /// the return value will be std::nullopt. + /// \param[in] _topic The name of the topic to get statistics for. + /// \return A TopicStatistics class, or std::nullopt if statistics were + /// not enabled. + public: std::optional TopicStats( + const std::string &_topic) const; + + /// \brief Constructor. + protected: NodeShared(); + + /// \brief Destructor. + protected: virtual ~NodeShared(); + + /// \brief Initialize all sockets. + /// \return True when success or false otherwise. This function might + /// return false if any operation on a ZMQ socket triggered an exception. + private: bool InitializeSockets(); + + ////////////////////////////////////////////////// + /////// Declare here other member variables ////// + ////////////////////////////////////////////////// + + /// \brief Response receiver socket identity. + public: Uuid responseReceiverId; + + /// \brief Replier socket identity. + public: Uuid replierId; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -311,105 +309,105 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Process UUID. - public: std::string pUuid; + /// \brief Process UUID. + public: std::string pUuid; - /// \brief thread in charge of receiving and handling incoming messages. - public: std::thread threadReception; + /// \brief thread in charge of receiving and handling incoming messages. + public: std::thread threadReception; - /// \brief Mutex to guarantee exclusive access between all threads. - public: mutable std::recursive_mutex mutex; + /// \brief Mutex to guarantee exclusive access between all threads. + public: mutable std::recursive_mutex mutex; - /// \brief Default IP address used by the message discovery layer. - public: std::string discoveryIP = "239.255.0.7"; + /// \brief Default IP address used by the message discovery layer. + public: std::string discoveryIP = "239.255.0.7"; - /// \brief Default port used by the message discovery layer. - public: static const int kDefaultMsgDiscPort = 10317; + /// \brief Default port used by the message discovery layer. + public: static const int kDefaultMsgDiscPort = 10317; - /// \brief Default port used by the service discovery layer. - public: static const int kDefaultSrvDiscPort = 10318; + /// \brief Default port used by the service discovery layer. + public: static const int kDefaultSrvDiscPort = 10318; - /// \brief Port used by the message discovery layer. - public: int msgDiscPort = kDefaultMsgDiscPort; + /// \brief Port used by the message discovery layer. + public: int msgDiscPort = kDefaultMsgDiscPort; - /// \brief Port used by the service discovery layer. - public: int srvDiscPort = kDefaultSrvDiscPort; + /// \brief Port used by the service discovery layer. + public: int srvDiscPort = kDefaultSrvDiscPort; - /// \brief Remote connections for pub/sub messages. - private: TopicStorage connections; + /// \brief Remote connections for pub/sub messages. + private: TopicStorage connections; - /// \brief List of connected zmq end points for request/response. - private: std::vector srvConnections; + /// \brief List of connected zmq end points for request/response. + private: std::vector srvConnections; - /// \brief Remote subscribers. - public: TopicStorage remoteSubscribers; + /// \brief Remote subscribers. + public: TopicStorage remoteSubscribers; #ifdef _WIN32 #pragma warning(pop) #endif - /// \brief This struct wraps up the two different types of subscription - /// handlers: normal (deserialized) and raw (serialized). This wrapper - /// keeps the two sets of subscription handlers coordinated while allowing - /// them to act independently when necessary. - struct HandlerWrapper - { - /// \brief Returns true if this wrapper contains any subscriber that - /// matches the given topic name and message type name. - /// \param[in] _fullyQualifiedTopic Fully-qualified topic name - /// \param[in] _msgType Name of message type - /// \return True if this contains a matching subscriber, otherwise false - /// \sa TopicUtils::FullyQualifiedName - public: bool HasSubscriber( - const std::string &_fullyQualifiedTopic, - const std::string &_msgType) const; - - /// \brief Returns true if this wrapper contains any subscriber that - /// matches the given fully-qualified topic name. The message type name - /// of the subscriber is irrelevant. - /// \param[in] _fullyQualifiedTopic Fully-qualified topic name - /// \return True if this contains a matching subscriber, otherwise false - public: bool HasSubscriber( - const std::string &_fullyQualifiedTopic) const; - - /// \brief Get a set of node UUIDs for subscribers in this wrapper that - /// match the topic and message type criteria. - /// \param[in] _fullyQualifiedTopic Fully-qualified topic name that the - /// subscribers must be listening to. - /// \param[in] _msgTypeName Name of the message type that the - /// subscribers must be listening for. - /// \return The node UUIDs of all subscribers that match the criteria - public: std::vector NodeUuids( - const std::string &_fullyQualifiedTopic, - const std::string &_msgTypeName) const; - - /// \brief Remove the handlers for the given topic name that belong to - /// a specific node. - /// \param[in] _fullyQualifiedTopic The fully-qualified name of the - /// topic whose subscribers should be removed. - /// \param[in] _nUuid The UUID of the node whose subscribers should be - /// removed. - /// \return True if at least one subscriber was removed. - public: bool RemoveHandlersForNode( - const std::string &_fullyQualifiedTopic, - const std::string &_nUuid); - - /// \brief Convert all the HandlerStorages into a vector of publishers. - /// \param[in] _addr The pub/sub address. - /// \param[in] _pUuid The process UUID. - /// \return The vector of message publishers. - public: std::vector Convert(const std::string &_addr, - const std::string &_pUuid); - - /// \brief Normal local subscriptions. - public: HandlerStorage normal; - - /// \brief Raw local subscriptions. Keeping these separate from - /// localSubscriptions allows us to avoid an unnecessary deserialization - /// followed by an immediate reserialization. - public: HandlerStorage raw; - }; - - public: HandlerWrapper localSubscribers; + /// \brief This struct wraps up the two different types of subscription + /// handlers: normal (deserialized) and raw (serialized). This wrapper + /// keeps the two sets of subscription handlers coordinated while allowing + /// them to act independently when necessary. + struct HandlerWrapper + { + /// \brief Returns true if this wrapper contains any subscriber that + /// matches the given topic name and message type name. + /// \param[in] _fullyQualifiedTopic Fully-qualified topic name + /// \param[in] _msgType Name of message type + /// \return True if this contains a matching subscriber, otherwise false + /// \sa TopicUtils::FullyQualifiedName + public: bool HasSubscriber( + const std::string &_fullyQualifiedTopic, + const std::string &_msgType) const; + + /// \brief Returns true if this wrapper contains any subscriber that + /// matches the given fully-qualified topic name. The message type name + /// of the subscriber is irrelevant. + /// \param[in] _fullyQualifiedTopic Fully-qualified topic name + /// \return True if this contains a matching subscriber, otherwise false + public: bool HasSubscriber( + const std::string &_fullyQualifiedTopic) const; + + /// \brief Get a set of node UUIDs for subscribers in this wrapper that + /// match the topic and message type criteria. + /// \param[in] _fullyQualifiedTopic Fully-qualified topic name that the + /// subscribers must be listening to. + /// \param[in] _msgTypeName Name of the message type that the + /// subscribers must be listening for. + /// \return The node UUIDs of all subscribers that match the criteria + public: std::vector NodeUuids( + const std::string &_fullyQualifiedTopic, + const std::string &_msgTypeName) const; + + /// \brief Remove the handlers for the given topic name that belong to + /// a specific node. + /// \param[in] _fullyQualifiedTopic The fully-qualified name of the + /// topic whose subscribers should be removed. + /// \param[in] _nUuid The UUID of the node whose subscribers should be + /// removed. + /// \return True if at least one subscriber was removed. + public: bool RemoveHandlersForNode( + const std::string &_fullyQualifiedTopic, + const std::string &_nUuid); + + /// \brief Convert all the HandlerStorages into a vector of publishers. + /// \param[in] _addr The pub/sub address. + /// \param[in] _pUuid The process UUID. + /// \return The vector of message publishers. + public: std::vector Convert(const std::string &_addr, + const std::string &_pUuid); + + /// \brief Normal local subscriptions. + public: HandlerStorage normal; + + /// \brief Raw local subscriptions. Keeping these separate from + /// localSubscriptions allows us to avoid an unnecessary deserialization + /// followed by an immediate reserialization. + public: HandlerStorage raw; + }; + + public: HandlerWrapper localSubscribers; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -417,39 +415,38 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Service call repliers. - public: HandlerStorage repliers; + /// \brief Service call repliers. + public: HandlerStorage repliers; - /// \brief Pending service call requests. - public: HandlerStorage requests; + /// \brief Pending service call requests. + public: HandlerStorage requests; - /// \brief Print activity to stdout. - public: int verbose; + /// \brief Print activity to stdout. + public: int verbose; - /// \brief My pub/sub address. - public: std::string myAddress; + /// \brief My pub/sub address. + public: std::string myAddress; - /// \brief My pub/sub control address. - public: std::string myControlAddress; + /// \brief My pub/sub control address. + public: std::string myControlAddress; - /// \brief My requester service call address. - public: std::string myRequesterAddress; + /// \brief My requester service call address. + public: std::string myRequesterAddress; - /// \brief My replier service call address. - public: std::string myReplierAddress; + /// \brief My replier service call address. + public: std::string myReplierAddress; - /// \brief IP address of this host. - public: std::string hostAddr; + /// \brief IP address of this host. + public: std::string hostAddr; - /// \brief Internal data pointer. - private: std::unique_ptr dataPtr; + /// \brief Internal data pointer. + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - private: friend Node; - private: friend NodePrivate; - }; - } - } -} -#endif + private: friend Node; + private: friend NodePrivate; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_NODESHARED_HH_ diff --git a/include/gz/transport/Publisher.hh b/include/gz/transport/Publisher.hh index 8e987e719..e34df056d 100644 --- a/include/gz/transport/Publisher.hh +++ b/include/gz/transport/Publisher.hh @@ -27,127 +27,125 @@ #include "gz/transport/config.hh" #include "gz/transport/Export.hh" -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + // Forward declarations. + class MessagePublisherPrivate; + + /// \class Publisher Publisher.hh + /// gz/transport/Publisher.hh + /// \brief This class stores all the information about a publisher. + /// It stores the topic name that publishes, addresses, UUIDs, scope, etc. + class GZ_TRANSPORT_VISIBLE Publisher { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - // Forward declarations. - class MessagePublisherPrivate; - - /// \class Publisher Publisher.hh - /// gz/transport/Publisher.hh - /// \brief This class stores all the information about a publisher. - /// It stores the topic name that publishes, addresses, UUIDs, scope, etc. - class GZ_TRANSPORT_VISIBLE Publisher + /// \brief Default constructor. + public: Publisher() = default; + + /// \brief Constructor. + /// \param[in] _topic Topic name. + /// \param[in] _addr ZeroMQ address. + /// \param[in] _pUuid Process UUID. + /// \param[in] _nUuid node UUID. + /// \param[in] _opts The advertise options. + public: Publisher(const std::string &_topic, + const std::string &_addr, + const std::string &_pUuid, + const std::string &_nUuid, + const AdvertiseOptions &_opts); + + /// \brief Destructor. + public: virtual ~Publisher() = default; + + /// \brief Get the topic published by this publisher. + /// \return Topic name. + /// \sa SetTopic. + public: std::string Topic() const; + + /// \brief Get the ZeroMQ address of the publisher. + /// \return ZeroMQ address. + /// \sa SetAddr. + public: std::string Addr() const; + + /// \brief Get the process UUID of the publisher. + /// return Process UUID. + /// \sa SetPUuid. + public: std::string PUuid() const; + + /// \brief Get the node UUID of the publisher. + /// \return Node UUID. + /// \sa SetNUuid. + public: std::string NUuid() const; + + /// \brief Get the advertised options. + /// \return The advertised options. + /// \sa SetOptions. + public: virtual const AdvertiseOptions &Options() const; + + /// \brief Set the topic name published by this publisher. + /// \param[in] _topic New topic name. + /// \sa Topic. + public: void SetTopic(const std::string &_topic); + + /// \brief Set ZeroMQ address of the publisher. + /// \param[in] _addr New address. + /// \sa Addr. + public: void SetAddr(const std::string &_addr); + + /// \brief Set the process UUID of the publisher. + /// \param[in] _pUuid New process UUID. + /// \sa PUuid. + public: void SetPUuid(const std::string &_pUuid); + + /// \brief Set the node UUID of the publisher. + /// \param[in] _nUuid New node UUID. + /// \sa NUuid. + public: void SetNUuid(const std::string &_nUuid); + + /// \brief Set the advertised options. + /// \param[in] _opts New advertised options. + /// \sa Options. + public: void SetOptions(const AdvertiseOptions &_opts); + + /// \brief Populate a discovery message. + /// \param[in] _msg Message to fill. + public: virtual void FillDiscovery(msgs::Discovery &_msg) const; + + /// \brief Set data from a discovery message. + /// \param[in] _msg Discovery message. + public: virtual void SetFromDiscovery(const msgs::Discovery &_msg); + + /// \brief Equality operator. This function checks if the given + /// publisher has identical Topic, Addr, PUuid, NUuid, and Scope + /// strings to this object. + /// \param[in] _pub The publisher to compare against. + /// \return True if this object matches the provided object. + public: bool operator==(const Publisher &_pub) const; + + /// \brief Inequality operator. This function checks if the given + /// publisher does not have identical Topic, Addr, PUuid, NUuid, and Scope + /// strings to this object. + /// \param[in] _pub The publisher to compare against. + /// \return True if this object does not match the provided object. + public: bool operator!=(const Publisher &_pub) const; + + /// \brief Stream insertion operator. + /// \param[out] _out The output stream. + /// \param[in] _msg Publisher to write to the stream. + public: friend std::ostream &operator<<(std::ostream &_out, + const Publisher &_msg) { - /// \brief Default constructor. - public: Publisher() = default; - - /// \brief Constructor. - /// \param[in] _topic Topic name. - /// \param[in] _addr ZeroMQ address. - /// \param[in] _pUuid Process UUID. - /// \param[in] _nUuid node UUID. - /// \param[in] _opts The advertise options. - public: Publisher(const std::string &_topic, - const std::string &_addr, - const std::string &_pUuid, - const std::string &_nUuid, - const AdvertiseOptions &_opts); - - /// \brief Destructor. - public: virtual ~Publisher() = default; - - /// \brief Get the topic published by this publisher. - /// \return Topic name. - /// \sa SetTopic. - public: std::string Topic() const; - - /// \brief Get the ZeroMQ address of the publisher. - /// \return ZeroMQ address. - /// \sa SetAddr. - public: std::string Addr() const; - - /// \brief Get the process UUID of the publisher. - /// return Process UUID. - /// \sa SetPUuid. - public: std::string PUuid() const; - - /// \brief Get the node UUID of the publisher. - /// \return Node UUID. - /// \sa SetNUuid. - public: std::string NUuid() const; - - /// \brief Get the advertised options. - /// \return The advertised options. - /// \sa SetOptions. - public: virtual const AdvertiseOptions &Options() const; - - /// \brief Set the topic name published by this publisher. - /// \param[in] _topic New topic name. - /// \sa Topic. - public: void SetTopic(const std::string &_topic); - - /// \brief Set ZeroMQ address of the publisher. - /// \param[in] _addr New address. - /// \sa Addr. - public: void SetAddr(const std::string &_addr); - - /// \brief Set the process UUID of the publisher. - /// \param[in] _pUuid New process UUID. - /// \sa PUuid. - public: void SetPUuid(const std::string &_pUuid); - - /// \brief Set the node UUID of the publisher. - /// \param[in] _nUuid New node UUID. - /// \sa NUuid. - public: void SetNUuid(const std::string &_nUuid); - - /// \brief Set the advertised options. - /// \param[in] _opts New advertised options. - /// \sa Options. - public: void SetOptions(const AdvertiseOptions &_opts); - - /// \brief Populate a discovery message. - /// \param[in] _msg Message to fill. - public: virtual void FillDiscovery(msgs::Discovery &_msg) const; - - /// \brief Set data from a discovery message. - /// \param[in] _msg Discovery message. - public: virtual void SetFromDiscovery(const msgs::Discovery &_msg); - - /// \brief Equality operator. This function checks if the given - /// publisher has identical Topic, Addr, PUuid, NUuid, and Scope - /// strings to this object. - /// \param[in] _pub The publisher to compare against. - /// \return True if this object matches the provided object. - public: bool operator==(const Publisher &_pub) const; - - /// \brief Inequality operator. This function checks if the given - /// publisher does not have identical Topic, Addr, PUuid, NUuid, and Scope - /// strings to this object. - /// \param[in] _pub The publisher to compare against. - /// \return True if this object does not match the provided object. - public: bool operator!=(const Publisher &_pub) const; - - /// \brief Stream insertion operator. - /// \param[out] _out The output stream. - /// \param[in] _msg Publisher to write to the stream. - public: friend std::ostream &operator<<(std::ostream &_out, - const Publisher &_msg) - { - _out << "Publisher:" << std::endl - << "\tTopic: [" << _msg.Topic() << "]" << std::endl - << "\tAddress: " << _msg.Addr() << std::endl - << "\tProcess UUID: " << _msg.PUuid() << std::endl - << "\tNode UUID: " << _msg.NUuid() << std::endl - << _msg.Options(); - - return _out; - } + _out << "Publisher:" << std::endl + << "\tTopic: [" << _msg.Topic() << "]" << std::endl + << "\tAddress: " << _msg.Addr() << std::endl + << "\tProcess UUID: " << _msg.PUuid() << std::endl + << "\tNode UUID: " << _msg.NUuid() << std::endl + << _msg.Options(); + + return _out; + } #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -155,121 +153,121 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Topic name. - protected: std::string topic; + /// \brief Topic name. + protected: std::string topic; - /// \brief ZeroMQ address of the publisher. - protected: std::string addr; + /// \brief ZeroMQ address of the publisher. + protected: std::string addr; - /// \brief Process UUID of the publisher. - protected: std::string pUuid; + /// \brief Process UUID of the publisher. + protected: std::string pUuid; - /// \brief Node UUID of the publisher. - protected: std::string nUuid; + /// \brief Node UUID of the publisher. + protected: std::string nUuid; #ifdef _WIN32 #pragma warning(pop) #endif - /// \brief Advertised options. - /// This member is not used when we have a derived publisher. - private: AdvertiseOptions opts; - }; + /// \brief Advertised options. + /// This member is not used when we have a derived publisher. + private: AdvertiseOptions opts; + }; - /// \class MessagePublisher Publisher.hh - /// gz/transport/Publisher.hh - /// \brief This class stores all the information about a message publisher. - class GZ_TRANSPORT_VISIBLE MessagePublisher : public Publisher + /// \class MessagePublisher Publisher.hh + /// gz/transport/Publisher.hh + /// \brief This class stores all the information about a message publisher. + class GZ_TRANSPORT_VISIBLE MessagePublisher : public Publisher + { + /// \brief Default constructor. + public: MessagePublisher() = default; + + /// \brief Constructor. + /// \param[in] _topic Topic name. + /// \param[in] _addr ZeroMQ address. + /// \param[in] _ctrl ZeroMQ control address. + /// \param[in] _pUuid Process UUID. + /// \param[in] _nUuid node UUID. + /// \param[in] _msgTypeName Message type advertised by this publisher. + /// \param[in] _opts Advertise options. + public: explicit MessagePublisher(const std::string &_topic, + const std::string &_addr, + const std::string &_ctrl, + const std::string &_pUuid, + const std::string &_nUuid, + const std::string &_msgTypeName, + const AdvertiseMessageOptions &_opts); + + /// \brief Destructor. + public: virtual ~MessagePublisher() = default; + + /// \brief Get the ZeroMQ control address. This address is used by the + /// subscribers to notify the publisher about the new subscription. + /// \return ZeroMQ control address of the publisher. + /// \sa SetCtrl. + public: std::string Ctrl() const; + + /// \brief Set the ZeroMQ control address of the publisher. + /// \param[in] _ctrl New control address. + /// \sa Ctrl. + public: void SetCtrl(const std::string &_ctrl); + + /// \brief Get the message type advertised by this publisher. + /// \return Message type. + public: std::string MsgTypeName() const; + + /// \brief Set the message type advertised by this publisher. + /// \param[in] _msgTypeName New message type. + /// \sa MsgTypeName. + public: void SetMsgTypeName(const std::string &_msgTypeName); + + /// \brief Get the advertised options. + /// \return The advertised options. + /// \sa SetOptions. + public: virtual const AdvertiseMessageOptions &Options() const; + + /// \brief Set the advertised options. + /// \param[in] _opts New advertised options. + /// \sa Options. + public: void SetOptions(const AdvertiseMessageOptions &_opts); + + /// \brief Populate a discovery message. + /// \param[in] _msg Message to fill. + public: virtual void FillDiscovery(msgs::Discovery &_msg) const final; + + /// \brief Set data from a discovery message. + /// \param[in] _msg Discovery message. + public: virtual void SetFromDiscovery(const msgs::Discovery &_msg); + + /// \brief Stream insertion operator. + /// \param[out] _out The output stream. + /// \param[in] _msg MessagePublisher to write to the stream. + public: friend std::ostream &operator<<(std::ostream &_out, + const MessagePublisher &_msg) { - /// \brief Default constructor. - public: MessagePublisher() = default; - - /// \brief Constructor. - /// \param[in] _topic Topic name. - /// \param[in] _addr ZeroMQ address. - /// \param[in] _ctrl ZeroMQ control address. - /// \param[in] _pUuid Process UUID. - /// \param[in] _nUuid node UUID. - /// \param[in] _msgTypeName Message type advertised by this publisher. - /// \param[in] _opts Advertise options. - public: explicit MessagePublisher(const std::string &_topic, - const std::string &_addr, - const std::string &_ctrl, - const std::string &_pUuid, - const std::string &_nUuid, - const std::string &_msgTypeName, - const AdvertiseMessageOptions &_opts); - - /// \brief Destructor. - public: virtual ~MessagePublisher() = default; - - /// \brief Get the ZeroMQ control address. This address is used by the - /// subscribers to notify the publisher about the new subscription. - /// \return ZeroMQ control address of the publisher. - /// \sa SetCtrl. - public: std::string Ctrl() const; - - /// \brief Set the ZeroMQ control address of the publisher. - /// \param[in] _ctrl New control address. - /// \sa Ctrl. - public: void SetCtrl(const std::string &_ctrl); - - /// \brief Get the message type advertised by this publisher. - /// \return Message type. - public: std::string MsgTypeName() const; - - /// \brief Set the message type advertised by this publisher. - /// \param[in] _msgTypeName New message type. - /// \sa MsgTypeName. - public: void SetMsgTypeName(const std::string &_msgTypeName); - - /// \brief Get the advertised options. - /// \return The advertised options. - /// \sa SetOptions. - public: virtual const AdvertiseMessageOptions &Options() const; - - /// \brief Set the advertised options. - /// \param[in] _opts New advertised options. - /// \sa Options. - public: void SetOptions(const AdvertiseMessageOptions &_opts); - - /// \brief Populate a discovery message. - /// \param[in] _msg Message to fill. - public: virtual void FillDiscovery(msgs::Discovery &_msg) const final; - - /// \brief Set data from a discovery message. - /// \param[in] _msg Discovery message. - public: virtual void SetFromDiscovery(const msgs::Discovery &_msg); - - /// \brief Stream insertion operator. - /// \param[out] _out The output stream. - /// \param[in] _msg MessagePublisher to write to the stream. - public: friend std::ostream &operator<<(std::ostream &_out, - const MessagePublisher &_msg) - { - _out << "Publisher:" << std::endl - << "\tTopic: [" << _msg.Topic() << "]" << std::endl - << "\tAddress: " << _msg.Addr() << std::endl - << "\tProcess UUID: " << _msg.PUuid() << std::endl - << "\tNode UUID: " << _msg.NUuid() << std::endl - << "\tControl address: " << _msg.Ctrl() << std::endl - << "\tMessage type: " << _msg.MsgTypeName() << std::endl - << _msg.Options(); - return _out; - } - - /// \brief Equality operator. This function checks if the given - /// message publisher has identical Topic, Addr, PUuid, NUuid, Scope, - /// Ctrl, and MsgTypeName strings to this object. - /// \param[in] _pub The message publisher to compare against. - /// \return True if this object matches the provided object. - public: bool operator==(const MessagePublisher &_pub) const; - - /// \brief Inequality operator. This function checks if the given - /// message publisher does not have identical Topic, Addr, PUuid, NUuid, - /// Scope, Ctrl, and MsgTypeName strings to this object. - /// \param[in] _pub The message publisher to compare against. - /// \return True if this object does not match the provided object. - public: bool operator!=(const MessagePublisher &_pub) const; + _out << "Publisher:" << std::endl + << "\tTopic: [" << _msg.Topic() << "]" << std::endl + << "\tAddress: " << _msg.Addr() << std::endl + << "\tProcess UUID: " << _msg.PUuid() << std::endl + << "\tNode UUID: " << _msg.NUuid() << std::endl + << "\tControl address: " << _msg.Ctrl() << std::endl + << "\tMessage type: " << _msg.MsgTypeName() << std::endl + << _msg.Options(); + return _out; + } + + /// \brief Equality operator. This function checks if the given + /// message publisher has identical Topic, Addr, PUuid, NUuid, Scope, + /// Ctrl, and MsgTypeName strings to this object. + /// \param[in] _pub The message publisher to compare against. + /// \return True if this object matches the provided object. + public: bool operator==(const MessagePublisher &_pub) const; + + /// \brief Inequality operator. This function checks if the given + /// message publisher does not have identical Topic, Addr, PUuid, NUuid, + /// Scope, Ctrl, and MsgTypeName strings to this object. + /// \param[in] _pub The message publisher to compare against. + /// \return True if this object does not match the provided object. + public: bool operator!=(const MessagePublisher &_pub) const; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -277,129 +275,129 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief ZeroMQ control address of the publisher. - private: std::string ctrl; + /// \brief ZeroMQ control address of the publisher. + private: std::string ctrl; - /// \brief Message type advertised by this publisher. - private: std::string msgTypeName; + /// \brief Message type advertised by this publisher. + private: std::string msgTypeName; #ifdef _WIN32 #pragma warning(pop) #endif - /// \brief Advertise options (e.g.: msgsPerSec). - private: AdvertiseMessageOptions msgOpts; - }; + /// \brief Advertise options (e.g.: msgsPerSec). + private: AdvertiseMessageOptions msgOpts; + }; - /// \class ServicePublisher Publisher.hh - /// gz/transport/Publisher.hh - /// \brief This class stores all the information about a service publisher. - class GZ_TRANSPORT_VISIBLE ServicePublisher : public Publisher + /// \class ServicePublisher Publisher.hh + /// gz/transport/Publisher.hh + /// \brief This class stores all the information about a service publisher. + class GZ_TRANSPORT_VISIBLE ServicePublisher : public Publisher + { + /// \brief Default constructor. + public: ServicePublisher() = default; + + /// \brief Constructor. + /// \param[in] _topic Topic name. + /// \param[in] _addr ZeroMQ address. + /// \param[in] _id ZeroMQ socket ID. + /// \param[in] _pUuid Process UUID. + /// \param[in] _nUuid node UUID. + /// \param[in] _reqType Message type used in the service request. + /// \param[in] _repType Message type used in the service response. + /// \param[in] _opts Advertise options. + public: ServicePublisher(const std::string &_topic, + const std::string &_addr, + const std::string &_id, + const std::string &_pUuid, + const std::string &_nUuid, + const std::string &_reqType, + const std::string &_repType, + const AdvertiseServiceOptions &_opts); + + /// \brief Destructor. + public: virtual ~ServicePublisher() = default; + + /// \brief Get the ZeroMQ socket ID used by this publisher. + /// \return The socket ID. + /// \sa SetSocketId. + public: std::string SocketId() const; + + /// \brief Set the ZeroMQ socket ID for this publisher. + /// \param[in] _socketId New socket ID. + /// \sa SocketId. + public: void SetSocketId(const std::string &_socketId); + + /// \brief Get the name of the request's protobuf message advertised. + /// \return The protobuf message type. + /// \sa SetReqTypeName. + public: std::string ReqTypeName() const; + + /// \brief Get the name of the response's protobuf message advertised. + /// \return The protobuf message type. + /// \sa SetRepTypeName. + public: std::string RepTypeName() const; + + /// \brief Set the name of the request's protobuf message advertised. + /// \param[in] _reqTypeName The protobuf message type. + /// \sa ReqTypeName. + public: void SetReqTypeName(const std::string &_reqTypeName); + + /// \brief Set the name of the response's protobuf message advertised. + /// \param[in] _repTypeName The protobuf message type. + /// \sa RepTypeName. + public: void SetRepTypeName(const std::string &_repTypeName); + + /// \brief Get the advertised options. + /// \return The advertised options. + /// \sa SetOptions. + public: virtual const AdvertiseServiceOptions& Options() const; + + /// \brief Set the advertised options. + /// \param[in] _opts New advertised options. + /// \sa Options. + public: void SetOptions(const AdvertiseServiceOptions &_opts); + + /// \brief Populate a discovery message. + /// \param[in] _msg Message to fill. + public: virtual void FillDiscovery(msgs::Discovery &_msg) const final; + + /// \brief Populate a discovery message. + /// \brief Set data from a discovery message. + /// \param[in] _msg Discovery message. + public: virtual void SetFromDiscovery(const msgs::Discovery &_msg); + + /// \brief Stream insertion operator. + /// \param[out] _out The output stream. + /// \param[in] _msg ServicePublisher to write to the stream. + public: friend std::ostream &operator<<(std::ostream &_out, + const ServicePublisher &_msg) { - /// \brief Default constructor. - public: ServicePublisher() = default; - - /// \brief Constructor. - /// \param[in] _topic Topic name. - /// \param[in] _addr ZeroMQ address. - /// \param[in] _id ZeroMQ socket ID. - /// \param[in] _pUuid Process UUID. - /// \param[in] _nUuid node UUID. - /// \param[in] _reqType Message type used in the service request. - /// \param[in] _repType Message type used in the service response. - /// \param[in] _opts Advertise options. - public: ServicePublisher(const std::string &_topic, - const std::string &_addr, - const std::string &_id, - const std::string &_pUuid, - const std::string &_nUuid, - const std::string &_reqType, - const std::string &_repType, - const AdvertiseServiceOptions &_opts); - - /// \brief Destructor. - public: virtual ~ServicePublisher() = default; - - /// \brief Get the ZeroMQ socket ID used by this publisher. - /// \return The socket ID. - /// \sa SetSocketId. - public: std::string SocketId() const; - - /// \brief Set the ZeroMQ socket ID for this publisher. - /// \param[in] _socketId New socket ID. - /// \sa SocketId. - public: void SetSocketId(const std::string &_socketId); - - /// \brief Get the name of the request's protobuf message advertised. - /// \return The protobuf message type. - /// \sa SetReqTypeName. - public: std::string ReqTypeName() const; - - /// \brief Get the name of the response's protobuf message advertised. - /// \return The protobuf message type. - /// \sa SetRepTypeName. - public: std::string RepTypeName() const; - - /// \brief Set the name of the request's protobuf message advertised. - /// \param[in] _reqTypeName The protobuf message type. - /// \sa ReqTypeName. - public: void SetReqTypeName(const std::string &_reqTypeName); - - /// \brief Set the name of the response's protobuf message advertised. - /// \param[in] _repTypeName The protobuf message type. - /// \sa RepTypeName. - public: void SetRepTypeName(const std::string &_repTypeName); - - /// \brief Get the advertised options. - /// \return The advertised options. - /// \sa SetOptions. - public: virtual const AdvertiseServiceOptions& Options() const; - - /// \brief Set the advertised options. - /// \param[in] _opts New advertised options. - /// \sa Options. - public: void SetOptions(const AdvertiseServiceOptions &_opts); - - /// \brief Populate a discovery message. - /// \param[in] _msg Message to fill. - public: virtual void FillDiscovery(msgs::Discovery &_msg) const final; - - /// \brief Populate a discovery message. - /// \brief Set data from a discovery message. - /// \param[in] _msg Discovery message. - public: virtual void SetFromDiscovery(const msgs::Discovery &_msg); - - /// \brief Stream insertion operator. - /// \param[out] _out The output stream. - /// \param[in] _msg ServicePublisher to write to the stream. - public: friend std::ostream &operator<<(std::ostream &_out, - const ServicePublisher &_msg) - { - _out << "Publisher:" << std::endl - << "\tTopic: [" << _msg.Topic() << "]" << std::endl - << "\tAddress: " << _msg.Addr() << std::endl - << "\tProcess UUID: " << _msg.PUuid() << std::endl - << "\tNode UUID: " << _msg.NUuid() << std::endl - << "\tSocket ID: " << _msg.SocketId() << std::endl - << "\tRequest type: " << _msg.ReqTypeName() << std::endl - << "\tResponse type: " << _msg.RepTypeName() << std::endl - << _msg.Options(); - - return _out; - } - - /// \brief Equality operator. This function checks if the given - /// service has identical Topic, Addr, PUuid, NUuid, Scope, - /// SocketId, ReqTypeName, RepTypeName strings to this object. - /// \param[in] _srv The service publisher to compare against. - /// \return True if this object matches the provided object. - public: bool operator==(const ServicePublisher &_srv) const; - - /// \brief Inequality operator. This function checks if the given - /// service does not have identical Topic, Addr, PUuid, NUuid, Scope, - /// SocketId, ReqTypeName, RepTypeName strings to this object. - /// \param[in] _srv The service publisher to compare against. - /// \return True if this object does not match the provided object. - public: bool operator!=(const ServicePublisher &_srv) const; + _out << "Publisher:" << std::endl + << "\tTopic: [" << _msg.Topic() << "]" << std::endl + << "\tAddress: " << _msg.Addr() << std::endl + << "\tProcess UUID: " << _msg.PUuid() << std::endl + << "\tNode UUID: " << _msg.NUuid() << std::endl + << "\tSocket ID: " << _msg.SocketId() << std::endl + << "\tRequest type: " << _msg.ReqTypeName() << std::endl + << "\tResponse type: " << _msg.RepTypeName() << std::endl + << _msg.Options(); + + return _out; + } + + /// \brief Equality operator. This function checks if the given + /// service has identical Topic, Addr, PUuid, NUuid, Scope, + /// SocketId, ReqTypeName, RepTypeName strings to this object. + /// \param[in] _srv The service publisher to compare against. + /// \return True if this object matches the provided object. + public: bool operator==(const ServicePublisher &_srv) const; + + /// \brief Inequality operator. This function checks if the given + /// service does not have identical Topic, Addr, PUuid, NUuid, Scope, + /// SocketId, ReqTypeName, RepTypeName strings to this object. + /// \param[in] _srv The service publisher to compare against. + /// \return True if this object does not match the provided object. + public: bool operator!=(const ServicePublisher &_srv) const; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -407,23 +405,21 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief ZeroMQ socket ID used by this publisher. - private: std::string socketId; + /// \brief ZeroMQ socket ID used by this publisher. + private: std::string socketId; - /// \brief The name of the request's protobuf message advertised. - private: std::string reqTypeName; + /// \brief The name of the request's protobuf message advertised. + private: std::string reqTypeName; - /// \brief The name of the response's protobuf message advertised. - private: std::string repTypeName; + /// \brief The name of the response's protobuf message advertised. + private: std::string repTypeName; #ifdef _WIN32 #pragma warning(pop) #endif - /// \brief Advertise options. - private: AdvertiseServiceOptions srvOpts; - }; - } - } -} - -#endif + /// \brief Advertise options. + private: AdvertiseServiceOptions srvOpts; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_PUBLISHER_HH_ diff --git a/include/gz/transport/RepHandler.hh b/include/gz/transport/RepHandler.hh index eb2e9d7c1..9e364452f 100644 --- a/include/gz/transport/RepHandler.hh +++ b/include/gz/transport/RepHandler.hh @@ -41,56 +41,54 @@ #include "gz/transport/TransportTypes.hh" #include "gz/transport/Uuid.hh" -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \class IRepHandler RepHandler.hh gz/transport/RepHandler.hh + /// \brief Interface class used to manage a replier handler. + class GZ_TRANSPORT_VISIBLE IRepHandler { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \class IRepHandler RepHandler.hh gz/transport/RepHandler.hh - /// \brief Interface class used to manage a replier handler. - class GZ_TRANSPORT_VISIBLE IRepHandler + /// \brief Constructor. + public: IRepHandler() + : hUuid(Uuid().ToString()) { - /// \brief Constructor. - public: IRepHandler() - : hUuid(Uuid().ToString()) - { - } + } - /// \brief Destructor. - public: virtual ~IRepHandler() = default; - - /// \brief Executes the local callback registered for this handler. - /// \param[in] _msgReq Input parameter (Protobuf message). - /// \param[out] _msgRep Output parameter (Protobuf message). - /// \return Service call result. - public: virtual bool RunLocalCallback(const transport::ProtoMsg &_msgReq, - transport::ProtoMsg &_msgRep) = 0; - - /// \brief Executes the callback registered for this handler. - /// \param[in] _req Serialized data received. The data will be used - /// to compose a specific protobuf message and will be passed to the - /// callback function. - /// \param[out] _rep Out parameter with the data serialized. - /// \return Service call result. - public: virtual bool RunCallback(const std::string &_req, - std::string &_rep) = 0; - - /// \brief Get the unique UUID of this handler. - /// \return a string representation of the handler UUID. - public: std::string HandlerUuid() const - { - return this->hUuid; - } + /// \brief Destructor. + public: virtual ~IRepHandler() = default; + + /// \brief Executes the local callback registered for this handler. + /// \param[in] _msgReq Input parameter (Protobuf message). + /// \param[out] _msgRep Output parameter (Protobuf message). + /// \return Service call result. + public: virtual bool RunLocalCallback(const transport::ProtoMsg &_msgReq, + transport::ProtoMsg &_msgRep) = 0; + + /// \brief Executes the callback registered for this handler. + /// \param[in] _req Serialized data received. The data will be used + /// to compose a specific protobuf message and will be passed to the + /// callback function. + /// \param[out] _rep Out parameter with the data serialized. + /// \return Service call result. + public: virtual bool RunCallback(const std::string &_req, + std::string &_rep) = 0; + + /// \brief Get the unique UUID of this handler. + /// \return a string representation of the handler UUID. + public: std::string HandlerUuid() const + { + return this->hUuid; + } - /// \brief Get the message type name used in the service request. - /// \return Message type name. - public: virtual std::string ReqTypeName() const = 0; + /// \brief Get the message type name used in the service request. + /// \return Message type name. + public: virtual std::string ReqTypeName() const = 0; - /// \brief Get the message type name used in the service response. - /// \return Message type name. - public: virtual std::string RepTypeName() const = 0; + /// \brief Get the message type name used in the service response. + /// \return Message type name. + public: virtual std::string RepTypeName() const = 0; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -98,133 +96,131 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Unique handler's UUID. - protected: std::string hUuid; + /// \brief Unique handler's UUID. + protected: std::string hUuid; #ifdef _WIN32 #pragma warning(pop) #endif - }; - - /// \class RepHandler RepHandler.hh - /// \brief It creates a service reply handler for a pair of protobuf - /// messages containing the request parameters and the response. - /// 'Req' is the protobuf message type containing the input parameters of - // the service call. 'Rep' is the protobuf message type that will be filled - /// with the service response. - template class RepHandler - : public IRepHandler + }; + + /// \class RepHandler RepHandler.hh + /// \brief It creates a service reply handler for a pair of protobuf + /// messages containing the request parameters and the response. + /// 'Req' is the protobuf message type containing the input parameters of + // the service call. 'Rep' is the protobuf message type that will be filled + /// with the service response. + template class RepHandler + : public IRepHandler + { + // Documentation inherited. + public: RepHandler() = default; + + /// \brief Set the callback for this handler. + /// \param[in] _cb The callback with the following parameters: + /// * _req Protobuf message containing the service request params + /// * _rep Protobuf message containing the service response. + /// * Returns true when the service response is considered + /// successful or false otherwise. + public: void SetCallback( + const std::function &_cb) { - // Documentation inherited. - public: RepHandler() = default; - - /// \brief Set the callback for this handler. - /// \param[in] _cb The callback with the following parameters: - /// * _req Protobuf message containing the service request params - /// * _rep Protobuf message containing the service response. - /// * Returns true when the service response is considered - /// successful or false otherwise. - public: void SetCallback( - const std::function &_cb) - { - this->cb = _cb; - } + this->cb = _cb; + } - // Documentation inherited. - public: bool RunLocalCallback(const transport::ProtoMsg &_msgReq, - transport::ProtoMsg &_msgRep) + // Documentation inherited. + public: bool RunLocalCallback(const transport::ProtoMsg &_msgReq, + transport::ProtoMsg &_msgRep) + { + // Execute the callback (if existing) + if (!this->cb) { - // Execute the callback (if existing) - if (!this->cb) - { - std::cerr << "RepHandler::RunLocalCallback() error: " - << "Callback is NULL" << std::endl; - return false; - } + std::cerr << "RepHandler::RunLocalCallback() error: " + << "Callback is NULL" << std::endl; + return false; + } #if GOOGLE_PROTOBUF_VERSION >= 4022000 - auto msgReq = - google::protobuf::internal::DownCast(&_msgReq); - auto msgRep = google::protobuf::internal::DownCast(&_msgRep); + auto msgReq = + google::protobuf::internal::DownCast(&_msgReq); + auto msgRep = google::protobuf::internal::DownCast(&_msgRep); #elif GOOGLE_PROTOBUF_VERSION > 2999999 - auto msgReq = google::protobuf::down_cast(&_msgReq); - auto msgRep = google::protobuf::down_cast(&_msgRep); + auto msgReq = google::protobuf::down_cast(&_msgReq); + auto msgRep = google::protobuf::down_cast(&_msgRep); #else - auto msgReq = - google::protobuf::internal::down_cast(&_msgReq); - auto msgRep = google::protobuf::internal::down_cast(&_msgRep); + auto msgReq = + google::protobuf::internal::down_cast(&_msgReq); + auto msgRep = google::protobuf::internal::down_cast(&_msgRep); #endif - return this->cb(*msgReq, *msgRep); - } + return this->cb(*msgReq, *msgRep); + } - // Documentation inherited. - public: bool RunCallback(const std::string &_req, - std::string &_rep) + // Documentation inherited. + public: bool RunCallback(const std::string &_req, + std::string &_rep) + { + // Check if we have a callback registered. + if (!this->cb) { - // Check if we have a callback registered. - if (!this->cb) - { - std::cerr << "RepHandler::RunCallback() error: " - << "Callback is NULL" << std::endl; - return false; - } - - // Instantiate the specific protobuf message associated to this topic. - auto msgReq = this->CreateMsg(_req); - if (!msgReq) - { - return false; - } - - Rep msgRep; - if (!this->cb(*msgReq, msgRep)) - return false; - - if (!msgRep.SerializeToString(&_rep)) - { - std::cerr << "RepHandler::RunCallback(): Error serializing the " - << "response" << std::endl; - return false; - } - - return true; + std::cerr << "RepHandler::RunCallback() error: " + << "Callback is NULL" << std::endl; + return false; } - // Documentation inherited. - public: virtual std::string ReqTypeName() const + // Instantiate the specific protobuf message associated to this topic. + auto msgReq = this->CreateMsg(_req); + if (!msgReq) { - return Req().GetTypeName(); + return false; } - // Documentation inherited. - public: virtual std::string RepTypeName() const + Rep msgRep; + if (!this->cb(*msgReq, msgRep)) + return false; + + if (!msgRep.SerializeToString(&_rep)) { - return Rep().GetTypeName(); + std::cerr << "RepHandler::RunCallback(): Error serializing the " + << "response" << std::endl; + return false; } - /// \brief Create a specific protobuf message given its serialized data. - /// \param[in] _data The serialized data. - /// \return Pointer to the specific protobuf message. - private: std::shared_ptr CreateMsg(const std::string &_data) const - { - // Instantiate a specific protobuf message - std::shared_ptr msgPtr(new Req()); + return true; + } + + // Documentation inherited. + public: virtual std::string ReqTypeName() const + { + return Req().GetTypeName(); + } - // Create the message using some serialized data - if (!msgPtr->ParseFromString(_data)) - { - std::cerr << "RepHandler::CreateMsg() error: ParseFromString failed" - << std::endl; - } + // Documentation inherited. + public: virtual std::string RepTypeName() const + { + return Rep().GetTypeName(); + } - return msgPtr; + /// \brief Create a specific protobuf message given its serialized data. + /// \param[in] _data The serialized data. + /// \return Pointer to the specific protobuf message. + private: std::shared_ptr CreateMsg(const std::string &_data) const + { + // Instantiate a specific protobuf message + std::shared_ptr msgPtr(new Req()); + + // Create the message using some serialized data + if (!msgPtr->ParseFromString(_data)) + { + std::cerr << "RepHandler::CreateMsg() error: ParseFromString failed" + << std::endl; } - /// \brief Callback to the function registered for this handler. - private: std::function cb; - }; + return msgPtr; } - } -} -#endif + /// \brief Callback to the function registered for this handler. + private: std::function cb; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_REPHANDLER_HH_ diff --git a/include/gz/transport/ReqHandler.hh b/include/gz/transport/ReqHandler.hh index bce02a7e0..fd84e92f3 100644 --- a/include/gz/transport/ReqHandler.hh +++ b/include/gz/transport/ReqHandler.hh @@ -37,114 +37,112 @@ #include "gz/transport/TransportTypes.hh" #include "gz/transport/Uuid.hh" -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \class IReqHandler ReqHandler.hh gz/transport/ReqHandler.hh + /// \brief Interface class used to manage a request handler. + class GZ_TRANSPORT_VISIBLE IReqHandler { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \class IReqHandler ReqHandler.hh gz/transport/ReqHandler.hh - /// \brief Interface class used to manage a request handler. - class GZ_TRANSPORT_VISIBLE IReqHandler + /// \brief Constructor. + /// \param[in] _nUuid UUID of the node registering the request handler. + public: explicit IReqHandler(const std::string &_nUuid) + : rep(""), + hUuid(Uuid().ToString()), + nUuid(_nUuid), + result(false), + requested(false), + repAvailable(false) { - /// \brief Constructor. - /// \param[in] _nUuid UUID of the node registering the request handler. - public: explicit IReqHandler(const std::string &_nUuid) - : rep(""), - hUuid(Uuid().ToString()), - nUuid(_nUuid), - result(false), - requested(false), - repAvailable(false) - { - } + } - /// \brief Destructor. - public: virtual ~IReqHandler() = default; - - /// \brief Executes the callback registered for this handler and notify - /// a potential requester waiting on a blocking call. - /// \param[in] _rep Serialized data containing the response coming from - /// the service call responser. - /// \param[in] _result Contains the result of the service call coming from - /// the service call responser. - public: virtual void NotifyResult(const std::string &_rep, - const bool _result) = 0; - - /// \brief Get the node UUID. - /// \return The string representation of the node UUID. - public: std::string NodeUuid() const - { - return this->nUuid; - } + /// \brief Destructor. + public: virtual ~IReqHandler() = default; + + /// \brief Executes the callback registered for this handler and notify + /// a potential requester waiting on a blocking call. + /// \param[in] _rep Serialized data containing the response coming from + /// the service call responser. + /// \param[in] _result Contains the result of the service call coming from + /// the service call responser. + public: virtual void NotifyResult(const std::string &_rep, + const bool _result) = 0; + + /// \brief Get the node UUID. + /// \return The string representation of the node UUID. + public: std::string NodeUuid() const + { + return this->nUuid; + } - /// \brief Get the service response as raw bytes. - /// \return The string containing the service response. - public: std::string Response() const - { - return this->rep; - } + /// \brief Get the service response as raw bytes. + /// \return The string containing the service response. + public: std::string Response() const + { + return this->rep; + } - /// \brief Get the result of the service response. - /// \return The boolean result. - public: bool Result() const - { - return this->result; - } + /// \brief Get the result of the service response. + /// \return The boolean result. + public: bool Result() const + { + return this->result; + } - /// \brief Returns if this service call request has already been requested - /// \return True when the service call has been requested. - public: bool Requested() const - { - return this->requested; - } + /// \brief Returns if this service call request has already been requested + /// \return True when the service call has been requested. + public: bool Requested() const + { + return this->requested; + } - /// \brief Mark the service call as requested (or not). - /// \param[in] _value true when you want to flag this REQ as requested. - public: void Requested(const bool _value) - { - this->requested = _value; - } + /// \brief Mark the service call as requested (or not). + /// \param[in] _value true when you want to flag this REQ as requested. + public: void Requested(const bool _value) + { + this->requested = _value; + } - /// \brief Serialize the Req protobuf message stored. - /// \param[out] _buffer The serialized data. - /// \return True if the serialization succeed or false otherwise. - public: virtual bool Serialize(std::string &_buffer) const = 0; + /// \brief Serialize the Req protobuf message stored. + /// \param[out] _buffer The serialized data. + /// \return True if the serialization succeed or false otherwise. + public: virtual bool Serialize(std::string &_buffer) const = 0; - /// \brief Returns the unique handler UUID. - /// \return The handler's UUID. - public: std::string HandlerUuid() const - { - return this->hUuid; - } + /// \brief Returns the unique handler UUID. + /// \return The handler's UUID. + public: std::string HandlerUuid() const + { + return this->hUuid; + } - /// \brief Block the current thread until the response to the - /// service request is available or until the timeout expires. - /// This method uses a condition variable to notify when the response is - /// available. - /// \param[in] _lock Lock used to protect the condition variable. - /// \param[in] _timeout Maximum waiting time in milliseconds. - /// \return True if the service call was executed or false otherwise. - public: template bool WaitUntil(Lock &_lock, - const unsigned int _timeout) - { - auto now = std::chrono::steady_clock::now(); - return this->condition.wait_until(_lock, - now + std::chrono::milliseconds(_timeout), - [this] - { - return this->repAvailable; - }); - } + /// \brief Block the current thread until the response to the + /// service request is available or until the timeout expires. + /// This method uses a condition variable to notify when the response is + /// available. + /// \param[in] _lock Lock used to protect the condition variable. + /// \param[in] _timeout Maximum waiting time in milliseconds. + /// \return True if the service call was executed or false otherwise. + public: template bool WaitUntil(Lock &_lock, + const unsigned int _timeout) + { + auto now = std::chrono::steady_clock::now(); + return this->condition.wait_until(_lock, + now + std::chrono::milliseconds(_timeout), + [this] + { + return this->repAvailable; + }); + } - /// \brief Get the message type name used in the service request. - /// \return Message type name. - public: virtual std::string ReqTypeName() const = 0; + /// \brief Get the message type name used in the service request. + /// \return Message type name. + public: virtual std::string ReqTypeName() const = 0; - /// \brief Get the message type name used in the service response. - /// \return Message type name. - public: virtual std::string RepTypeName() const = 0; + /// \brief Get the message type name used in the service response. + /// \return Message type name. + public: virtual std::string RepTypeName() const = 0; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -152,266 +150,264 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Condition variable used to wait until a service call REP is - /// available. - protected: std::condition_variable_any condition; + /// \brief Condition variable used to wait until a service call REP is + /// available. + protected: std::condition_variable_any condition; - /// \brief Stores the service response as raw bytes. - protected: std::string rep; + /// \brief Stores the service response as raw bytes. + protected: std::string rep; - /// \brief Unique handler's UUID. - protected: std::string hUuid; + /// \brief Unique handler's UUID. + protected: std::string hUuid; - /// \brief Node UUID. - private: std::string nUuid; + /// \brief Node UUID. + private: std::string nUuid; #ifdef _WIN32 #pragma warning(pop) #endif - /// \brief Stores the result of the service call. - protected: bool result; - - /// \brief When true, the REQ was already sent and the REP should be on - /// its way. Used to not resend the same REQ more than one time. - private: bool requested; - - /// \brief When there is a blocking service call request, the call can - /// be unlocked when a service call REP is available. This variable - /// captures if we have found a node that can satisty our request. - public: bool repAvailable; - }; - - /// \class ReqHandler ReqHandler.hh - /// \brief It creates a reply handler for the specific protobuf - /// messages used. 'Req' is a protobuf message type containing the input - /// parameters of the service request. 'Rep' is a protobuf message type - /// that will be filled with the service response. - template class ReqHandler - : public IReqHandler + /// \brief Stores the result of the service call. + protected: bool result; + + /// \brief When true, the REQ was already sent and the REP should be on + /// its way. Used to not resend the same REQ more than one time. + private: bool requested; + + /// \brief When there is a blocking service call request, the call can + /// be unlocked when a service call REP is available. This variable + /// captures if we have found a node that can satisty our request. + public: bool repAvailable; + }; + + /// \class ReqHandler ReqHandler.hh + /// \brief It creates a reply handler for the specific protobuf + /// messages used. 'Req' is a protobuf message type containing the input + /// parameters of the service request. 'Rep' is a protobuf message type + /// that will be filled with the service response. + template class ReqHandler + : public IReqHandler + { + // Documentation inherited. + public: explicit ReqHandler(const std::string &_nUuid) + : IReqHandler(_nUuid) { - // Documentation inherited. - public: explicit ReqHandler(const std::string &_nUuid) - : IReqHandler(_nUuid) - { - } + } + + /// \brief Create a specific protobuf message given its serialized data. + /// \param[in] _data The serialized data. + /// \return Pointer to the specific protobuf message. + public: std::shared_ptr CreateMsg(const std::string &_data) const + { + // Instantiate a specific protobuf message + std::shared_ptr msgPtr(new Rep()); - /// \brief Create a specific protobuf message given its serialized data. - /// \param[in] _data The serialized data. - /// \return Pointer to the specific protobuf message. - public: std::shared_ptr CreateMsg(const std::string &_data) const + // Create the message using some serialized data + if (!msgPtr->ParseFromString(_data)) { - // Instantiate a specific protobuf message - std::shared_ptr msgPtr(new Rep()); + std::cerr << "ReqHandler::CreateMsg() error: ParseFromString failed" + << std::endl; + } - // Create the message using some serialized data - if (!msgPtr->ParseFromString(_data)) - { - std::cerr << "ReqHandler::CreateMsg() error: ParseFromString failed" - << std::endl; - } + return msgPtr; + } - return msgPtr; - } + /// \brief Set the callback for this handler. + /// \param[in] _cb The callback with the following parameters: + /// * _rep Protobuf message containing the service response. + /// * _result True when the service request was successful or + /// false otherwise. + public: void SetCallback(const std::function &_cb) + { + this->cb = _cb; + } - /// \brief Set the callback for this handler. - /// \param[in] _cb The callback with the following parameters: - /// * _rep Protobuf message containing the service response. - /// * _result True when the service request was successful or - /// false otherwise. - public: void SetCallback(const std::function &_cb) + /// \brief Set the REQ protobuf message for this handler. + /// \param[in] _reqMsg Protofub message containing the input parameters of + /// of the service request. + public: void SetMessage(const Req *_reqMsg) + { + if (!_reqMsg) { - this->cb = _cb; + std::cerr << "ReqHandler::SetMessage() _reqMsg is null" << std::endl; + return; } - /// \brief Set the REQ protobuf message for this handler. - /// \param[in] _reqMsg Protofub message containing the input parameters of - /// of the service request. - public: void SetMessage(const Req *_reqMsg) - { - if (!_reqMsg) - { - std::cerr << "ReqHandler::SetMessage() _reqMsg is null" << std::endl; - return; - } + this->reqMsg.CopyFrom(*_reqMsg); + } - this->reqMsg.CopyFrom(*_reqMsg); - } + /// \brief This function is only used for compatibility with + /// SetResponse() when [REP = google::protobuf::Message]. + /// It shouldn't do anything. + /// \param[in] _repMsg Protofub message containing the variable where + /// the result will be stored. + public: void SetResponse(const Rep *_repMsg) + { + (void)_repMsg; + } - /// \brief This function is only used for compatibility with - /// SetResponse() when [REP = google::protobuf::Message]. - /// It shouldn't do anything. - /// \param[in] _repMsg Protofub message containing the variable where - /// the result will be stored. - public: void SetResponse(const Rep *_repMsg) + // Documentation inherited + public: bool Serialize(std::string &_buffer) const + { + if (!this->reqMsg.SerializeToString(&_buffer)) { - (void)_repMsg; + std::cerr << "ReqHandler::Serialize(): Error serializing the request" + << std::endl; + return false; } - // Documentation inherited - public: bool Serialize(std::string &_buffer) const + return true; + } + + // Documentation inherited. + public: void NotifyResult(const std::string &_rep, const bool _result) + { + // Execute the callback (if existing). + if (this->cb) { - if (!this->reqMsg.SerializeToString(&_buffer)) - { - std::cerr << "ReqHandler::Serialize(): Error serializing the request" - << std::endl; - return false; - } + // Instantiate the specific protobuf message associated to this topic. + auto msg = this->CreateMsg(_rep); - return true; + this->cb(*msg, _result); } - - // Documentation inherited. - public: void NotifyResult(const std::string &_rep, const bool _result) + else { - // Execute the callback (if existing). - if (this->cb) - { - // Instantiate the specific protobuf message associated to this topic. - auto msg = this->CreateMsg(_rep); + this->rep = _rep; + this->result = _result; + } - this->cb(*msg, _result); - } - else - { - this->rep = _rep; - this->result = _result; - } + this->repAvailable = true; + this->condition.notify_one(); + } - this->repAvailable = true; - this->condition.notify_one(); - } + // Documentation inherited. + public: virtual std::string ReqTypeName() const + { + return Req().GetTypeName(); + } - // Documentation inherited. - public: virtual std::string ReqTypeName() const - { - return Req().GetTypeName(); - } + // Documentation inherited. + public: virtual std::string RepTypeName() const + { + return Rep().GetTypeName(); + } - // Documentation inherited. - public: virtual std::string RepTypeName() const - { - return Rep().GetTypeName(); - } + /// \brief Protobuf message containing the request's parameters. + private: Req reqMsg; + + /// \brief Callback to the function registered for this handler with the + /// following parameters: + /// \param[in] _rep Protobuf message containing the service response. + /// \param[in] _result True when the service request was successful or + /// false otherwise. + private: std::function cb; + }; + + /// \class ReqHandler ReqHandler.hh + /// \brief Template specialization for google::protobuf::Message. + /// This is only used by some gz command line tools. + template <> class ReqHandler + : public IReqHandler + { + // Documentation inherited. + public: explicit ReqHandler(const std::string &_nUuid) + : IReqHandler(_nUuid) + { + } - /// \brief Protobuf message containing the request's parameters. - private: Req reqMsg; - - /// \brief Callback to the function registered for this handler with the - /// following parameters: - /// \param[in] _rep Protobuf message containing the service response. - /// \param[in] _result True when the service request was successful or - /// false otherwise. - private: std::function cb; - }; - - /// \class ReqHandler ReqHandler.hh - /// \brief Template specialization for google::protobuf::Message. - /// This is only used by some gz command line tools. - template <> class ReqHandler - : public IReqHandler + /// \brief Set the REQ protobuf message for this handler. + /// \param[in] _reqMsg Protofub message containing the input parameters of + /// of the service request. + public: void SetMessage(const google::protobuf::Message *_reqMsg) { - // Documentation inherited. - public: explicit ReqHandler(const std::string &_nUuid) - : IReqHandler(_nUuid) + if (!_reqMsg) { + std::cerr << "ReqHandler::SetMessage() _reqMsg is null" << std::endl; + return; } - /// \brief Set the REQ protobuf message for this handler. - /// \param[in] _reqMsg Protofub message containing the input parameters of - /// of the service request. - public: void SetMessage(const google::protobuf::Message *_reqMsg) - { - if (!_reqMsg) - { - std::cerr << "ReqHandler::SetMessage() _reqMsg is null" << std::endl; - return; - } + this->reqMsg = _reqMsg->New(); + this->reqMsg->CopyFrom(*_reqMsg); + } - this->reqMsg = _reqMsg->New(); - this->reqMsg->CopyFrom(*_reqMsg); + /// \brief Set the REP protobuf message for this handler. + /// \param[in] _repMsg Protofub message containing the variable where + /// the result will be stored. The only purpose of this function is to + /// store the type information of _repMsg. + public: void SetResponse(const google::protobuf::Message *_repMsg) + { + if (!_repMsg) + { + std::cerr << "ReqHandler::SetResponse() _repMsg is null" << std::endl; + return; } - /// \brief Set the REP protobuf message for this handler. - /// \param[in] _repMsg Protofub message containing the variable where - /// the result will be stored. The only purpose of this function is to - /// store the type information of _repMsg. - public: void SetResponse(const google::protobuf::Message *_repMsg) - { - if (!_repMsg) - { - std::cerr << "ReqHandler::SetResponse() _repMsg is null" << std::endl; - return; - } + this->repMsg = _repMsg->New(); + this->repMsg->CopyFrom(*_repMsg); + } - this->repMsg = _repMsg->New(); - this->repMsg->CopyFrom(*_repMsg); + // Documentation inherited + public: bool Serialize(std::string &_buffer) const + { + if (!this->reqMsg) + { + std::cerr << "ReqHandler::Serialize() reqMsg is null" << std::endl; + return false; } - // Documentation inherited - public: bool Serialize(std::string &_buffer) const + if (!this->reqMsg->SerializeToString(&_buffer)) { - if (!this->reqMsg) - { - std::cerr << "ReqHandler::Serialize() reqMsg is null" << std::endl; - return false; - } - - if (!this->reqMsg->SerializeToString(&_buffer)) - { - std::cerr << "ReqHandler::Serialize(): Error serializing the request" - << std::endl; - return false; - } - - return true; + std::cerr << "ReqHandler::Serialize(): Error serializing the request" + << std::endl; + return false; } - // Documentation inherited. - public: void NotifyResult(const std::string &_rep, const bool _result) - { - this->rep = _rep; - this->result = _result; + return true; + } - this->repAvailable = true; - this->condition.notify_one(); - } + // Documentation inherited. + public: void NotifyResult(const std::string &_rep, const bool _result) + { + this->rep = _rep; + this->result = _result; + + this->repAvailable = true; + this->condition.notify_one(); + } - // Documentation inherited. - public: virtual std::string ReqTypeName() const + // Documentation inherited. + public: virtual std::string ReqTypeName() const + { + if (this->reqMsg) + return this->reqMsg->GetTypeName(); + else { - if (this->reqMsg) - return this->reqMsg->GetTypeName(); - else - { - std::cerr << "ReqHandler::ReqTypeName() Warning: Using ReqTypeName() " - << "without type information" << std::endl; - return ""; - } + std::cerr << "ReqHandler::ReqTypeName() Warning: Using ReqTypeName() " + << "without type information" << std::endl; + return ""; } + } - //// Documentation inherited. - public: virtual std::string RepTypeName() const + //// Documentation inherited. + public: virtual std::string RepTypeName() const + { + if (this->repMsg) + return this->repMsg->GetTypeName(); + else { - if (this->repMsg) - return this->repMsg->GetTypeName(); - else - { - std::cerr << "ReqHandler::RepTypeName() Warning: Using RepTypeName() " - << "without type information" << std::endl; - return ""; - } + std::cerr << "ReqHandler::RepTypeName() Warning: Using RepTypeName() " + << "without type information" << std::endl; + return ""; } - - /// \brief Protobuf message containing the request's parameters. - private: google::protobuf::Message *reqMsg = nullptr; - - /// \brief Protobuf message containing the response. - private: google::protobuf::Message *repMsg = nullptr; - }; } - } -} -#endif + /// \brief Protobuf message containing the request's parameters. + private: google::protobuf::Message *reqMsg = nullptr; + + /// \brief Protobuf message containing the response. + private: google::protobuf::Message *repMsg = nullptr; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_REQHANDLER_HH_ diff --git a/include/gz/transport/SubscribeOptions.hh b/include/gz/transport/SubscribeOptions.hh index 72cd78e66..2f6fdb3fa 100644 --- a/include/gz/transport/SubscribeOptions.hh +++ b/include/gz/transport/SubscribeOptions.hh @@ -24,47 +24,45 @@ #include "gz/transport/config.hh" #include "gz/transport/Export.hh" -namespace gz +namespace gz::transport { - namespace transport - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - class SubscribeOptionsPrivate; + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + class SubscribeOptionsPrivate; - /// \class SubscribeOptions SubscribeOptions.hh - /// gz/transport/SubscribeOptions.hh - /// \brief A class to provide different options for a subscription. - class GZ_TRANSPORT_VISIBLE SubscribeOptions - { - /// \brief Constructor. - public: SubscribeOptions(); + /// \class SubscribeOptions SubscribeOptions.hh + /// gz/transport/SubscribeOptions.hh + /// \brief A class to provide different options for a subscription. + class GZ_TRANSPORT_VISIBLE SubscribeOptions + { + /// \brief Constructor. + public: SubscribeOptions(); - /// \brief Copy constructor. - /// \param[in] _otherSubscribeOpts SubscribeOptions to copy. - public: SubscribeOptions(const SubscribeOptions &_otherSubscribeOpts); + /// \brief Copy constructor. + /// \param[in] _otherSubscribeOpts SubscribeOptions to copy. + public: SubscribeOptions(const SubscribeOptions &_otherSubscribeOpts); - /// \brief Destructor. - public: ~SubscribeOptions(); + /// \brief Destructor. + public: ~SubscribeOptions(); - /// \brief Whether the subscription has been throttled. - /// \return true when the subscription is throttled or false otherwise. - /// \sa SetMsgsPerSec - /// \sa MsgsPerSec - public: bool Throttled() const; + /// \brief Whether the subscription has been throttled. + /// \return true when the subscription is throttled or false otherwise. + /// \sa SetMsgsPerSec + /// \sa MsgsPerSec + public: bool Throttled() const; - /// \brief Set the maximum number of messages per second received per - /// topic. Note that we calculate the minimum period of a message based - /// on the msgs/sec rate. Any message received since the last subscription - /// callback and the duration of the period will be discarded. - /// \param[in] _newMsgsPerSec Maximum number of messages per second. - public: void SetMsgsPerSec(const uint64_t _newMsgsPerSec); + /// \brief Set the maximum number of messages per second received per + /// topic. Note that we calculate the minimum period of a message based + /// on the msgs/sec rate. Any message received since the last subscription + /// callback and the duration of the period will be discarded. + /// \param[in] _newMsgsPerSec Maximum number of messages per second. + public: void SetMsgsPerSec(const uint64_t _newMsgsPerSec); - /// \brief Get the maximum number of messages per seconds received per - /// topic. - /// \return The maximum number of messages per second. - public: uint64_t MsgsPerSec() const; + /// \brief Get the maximum number of messages per seconds received per + /// topic. + /// \return The maximum number of messages per second. + public: uint64_t MsgsPerSec() const; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -72,14 +70,13 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal - /// \brief Pointer to private data. - protected: std::unique_ptr dataPtr; + /// \internal + /// \brief Pointer to private data. + protected: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } -} + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport #endif diff --git a/include/gz/transport/SubscriptionHandler.hh b/include/gz/transport/SubscriptionHandler.hh index 9e4d789b8..7da1458c0 100644 --- a/include/gz/transport/SubscriptionHandler.hh +++ b/include/gz/transport/SubscriptionHandler.hh @@ -46,51 +46,49 @@ #include "gz/transport/TransportTypes.hh" #include "gz/transport/Uuid.hh" -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \brief SubscriptionHandlerBase contains functions and data which are + /// common to all SubscriptionHandler types. + class GZ_TRANSPORT_VISIBLE SubscriptionHandlerBase { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \brief SubscriptionHandlerBase contains functions and data which are - /// common to all SubscriptionHandler types. - class GZ_TRANSPORT_VISIBLE SubscriptionHandlerBase - { - /// \brief Constructor. - /// \param[in] _nUuid UUID of the node registering the handler. - /// \param[in] _opts Subscription options. - public: explicit SubscriptionHandlerBase( - const std::string &_nUuid, - const SubscribeOptions &_opts = SubscribeOptions()); + /// \brief Constructor. + /// \param[in] _nUuid UUID of the node registering the handler. + /// \param[in] _opts Subscription options. + public: explicit SubscriptionHandlerBase( + const std::string &_nUuid, + const SubscribeOptions &_opts = SubscribeOptions()); - /// \brief Destructor. - public: virtual ~SubscriptionHandlerBase() = default; + /// \brief Destructor. + public: virtual ~SubscriptionHandlerBase() = default; - /// \brief Get the type of the messages from which this subscriber - /// handler is subscribed. - /// \return String representation of the message type. - public: virtual std::string TypeName() = 0; + /// \brief Get the type of the messages from which this subscriber + /// handler is subscribed. + /// \return String representation of the message type. + public: virtual std::string TypeName() = 0; - /// \brief Get the node UUID. - /// \return The string representation of the node UUID. - public: std::string NodeUuid() const; + /// \brief Get the node UUID. + /// \return The string representation of the node UUID. + public: std::string NodeUuid() const; - /// \brief Get the unique UUID of this handler. - /// \return A string representation of the handler UUID. - public: std::string HandlerUuid() const; + /// \brief Get the unique UUID of this handler. + /// \return A string representation of the handler UUID. + public: std::string HandlerUuid() const; - /// \brief Check if message subscription is throttled. If so, verify - /// whether the callback should be executed or not. - /// \return true if the callback should be executed or false otherwise. - protected: bool UpdateThrottling(); + /// \brief Check if message subscription is throttled. If so, verify + /// whether the callback should be executed or not. + /// \return true if the callback should be executed or false otherwise. + protected: bool UpdateThrottling(); - /// \brief Subscribe options. - protected: SubscribeOptions opts; + /// \brief Subscribe options. + protected: SubscribeOptions opts; - /// \brief If throttling is enabled, the minimum period for receiving a - /// message in nanoseconds. - protected: double periodNs; + /// \brief If throttling is enabled, the minimum period for receiving a + /// message in nanoseconds. + protected: double periodNs; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -98,257 +96,257 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Unique handler's UUID. - protected: std::string hUuid; + /// \brief Unique handler's UUID. + protected: std::string hUuid; - /// \brief Timestamp of the last callback executed. - protected: Timestamp lastCbTimestamp; + /// \brief Timestamp of the last callback executed. + protected: Timestamp lastCbTimestamp; - /// \brief Node UUID. - private: std::string nUuid; + /// \brief Node UUID. + private: std::string nUuid; #ifdef _WIN32 #pragma warning(pop) #endif - }; - - /// \class ISubscriptionHandler SubscriptionHandler.hh - /// gz/transport/SubscriptionHandler.hh - /// \brief Interface class used to manage generic protobuf messages. - /// - /// This extends SubscriptionHandlerBase by defining virtual functions for - /// deserializing protobuf message data, and for receiving deserialized - /// messages. Those functions are not needed by the RawSubscriptionHandler - /// class. - class GZ_TRANSPORT_VISIBLE ISubscriptionHandler - : public SubscriptionHandlerBase + }; + + /// \class ISubscriptionHandler SubscriptionHandler.hh + /// gz/transport/SubscriptionHandler.hh + /// \brief Interface class used to manage generic protobuf messages. + /// + /// This extends SubscriptionHandlerBase by defining virtual functions for + /// deserializing protobuf message data, and for receiving deserialized + /// messages. Those functions are not needed by the RawSubscriptionHandler + /// class. + class GZ_TRANSPORT_VISIBLE ISubscriptionHandler + : public SubscriptionHandlerBase + { + /// \brief Constructor. + /// \param[in] _nUuid UUID of the node registering the handler. + /// \param[in] _opts Subscription options. + public: explicit ISubscriptionHandler( + const std::string &_nUuid, + const SubscribeOptions &_opts = SubscribeOptions()); + + /// \brief Destructor. + public: virtual ~ISubscriptionHandler() = default; + + /// \brief Executes the local callback registered for this handler. + /// \param[in] _msg Protobuf message received. + /// \param[in] _info Message information (e.g.: topic name). + /// \return True when success, false otherwise. + public: virtual bool RunLocalCallback( + const ProtoMsg &_msg, + const MessageInfo &_info) = 0; + + /// \brief Create a specific protobuf message given its serialized data. + /// \param[in] _data The serialized data. + /// \param[in] _type The data type. + /// \return Pointer to the specific protobuf message. + public: virtual const std::shared_ptr CreateMsg( + const std::string &_data, + const std::string &_type) const = 0; + }; + + /// \class SubscriptionHandler SubscriptionHandler.hh + /// \brief It creates a subscription handler for a specific protobuf + /// message. 'T' is the Protobuf message type that will be used for this + /// particular handler. + template class SubscriptionHandler + : public ISubscriptionHandler + { + // Documentation inherited. + public: explicit SubscriptionHandler(const std::string &_nUuid, + const SubscribeOptions &_opts = SubscribeOptions()) + : ISubscriptionHandler(_nUuid, _opts) { - /// \brief Constructor. - /// \param[in] _nUuid UUID of the node registering the handler. - /// \param[in] _opts Subscription options. - public: explicit ISubscriptionHandler( - const std::string &_nUuid, - const SubscribeOptions &_opts = SubscribeOptions()); - - /// \brief Destructor. - public: virtual ~ISubscriptionHandler() = default; - - /// \brief Executes the local callback registered for this handler. - /// \param[in] _msg Protobuf message received. - /// \param[in] _info Message information (e.g.: topic name). - /// \return True when success, false otherwise. - public: virtual bool RunLocalCallback( - const ProtoMsg &_msg, - const MessageInfo &_info) = 0; - - /// \brief Create a specific protobuf message given its serialized data. - /// \param[in] _data The serialized data. - /// \param[in] _type The data type. - /// \return Pointer to the specific protobuf message. - public: virtual const std::shared_ptr CreateMsg( - const std::string &_data, - const std::string &_type) const = 0; - }; - - /// \class SubscriptionHandler SubscriptionHandler.hh - /// \brief It creates a subscription handler for a specific protobuf - /// message. 'T' is the Protobuf message type that will be used for this - /// particular handler. - template class SubscriptionHandler - : public ISubscriptionHandler + } + + // Documentation inherited. + public: const std::shared_ptr CreateMsg( + const std::string &_data, + const std::string &/*_type*/) const { - // Documentation inherited. - public: explicit SubscriptionHandler(const std::string &_nUuid, - const SubscribeOptions &_opts = SubscribeOptions()) - : ISubscriptionHandler(_nUuid, _opts) - { - } + // Instantiate a specific protobuf message + auto msgPtr = std::make_shared(); - // Documentation inherited. - public: const std::shared_ptr CreateMsg( - const std::string &_data, - const std::string &/*_type*/) const + // Create the message using some serialized data + if (!msgPtr->ParseFromString(_data)) { - // Instantiate a specific protobuf message - auto msgPtr = std::make_shared(); + std::cerr << "SubscriptionHandler::CreateMsg() error: ParseFromString" + << " failed" << std::endl; + } - // Create the message using some serialized data - if (!msgPtr->ParseFromString(_data)) - { - std::cerr << "SubscriptionHandler::CreateMsg() error: ParseFromString" - << " failed" << std::endl; - } + return msgPtr; + } - return msgPtr; - } + // Documentation inherited. + public: std::string TypeName() + { + return T().GetTypeName(); + } - // Documentation inherited. - public: std::string TypeName() - { - return T().GetTypeName(); - } + /// \brief Set the callback for this handler. + /// \param[in] _cb The callback with the following parameters: + public: void SetCallback(const MsgCallback &_cb) + { + this->cb = _cb; + } - /// \brief Set the callback for this handler. - /// \param[in] _cb The callback with the following parameters: - public: void SetCallback(const MsgCallback &_cb) + // Documentation inherited. + public: bool RunLocalCallback(const ProtoMsg &_msg, + const MessageInfo &_info) + { + // No callback stored. + if (!this->cb) { - this->cb = _cb; + std::cerr << "SubscriptionHandler::RunLocalCallback() error: " + << "Callback is NULL" << std::endl; + return false; } - // Documentation inherited. - public: bool RunLocalCallback(const ProtoMsg &_msg, - const MessageInfo &_info) - { - // No callback stored. - if (!this->cb) - { - std::cerr << "SubscriptionHandler::RunLocalCallback() error: " - << "Callback is NULL" << std::endl; - return false; - } - - // Check the subscription throttling option. - if (!this->UpdateThrottling()) - return true; + // Check the subscription throttling option. + if (!this->UpdateThrottling()) + return true; #if GOOGLE_PROTOBUF_VERSION >= 4022000 - auto msgPtr = google::protobuf::internal::DownCast(&_msg); + auto msgPtr = google::protobuf::internal::DownCast(&_msg); #elif GOOGLE_PROTOBUF_VERSION >= 3000000 - auto msgPtr = google::protobuf::down_cast(&_msg); + auto msgPtr = google::protobuf::down_cast(&_msg); #else - auto msgPtr = google::protobuf::internal::down_cast(&_msg); + auto msgPtr = google::protobuf::internal::down_cast(&_msg); #endif - this->cb(*msgPtr, _info); - return true; - } + this->cb(*msgPtr, _info); + return true; + } + + /// \brief Callback to the function registered for this handler. + private: MsgCallback cb; + }; - /// \brief Callback to the function registered for this handler. - private: MsgCallback cb; - }; + /// \brief Specialized template when the user prefers a callbacks that + /// accepts a generic google::protobuf::message instead of a specific type. + template <> class SubscriptionHandler + : public ISubscriptionHandler + { + // Documentation inherited. + public: explicit SubscriptionHandler(const std::string &_nUuid, + const SubscribeOptions &_opts = SubscribeOptions()) + : ISubscriptionHandler(_nUuid, _opts) + { + } - /// \brief Specialized template when the user prefers a callbacks that - /// accepts a generic google::protobuf::message instead of a specific type. - template <> class SubscriptionHandler - : public ISubscriptionHandler + // Documentation inherited. + public: const std::shared_ptr CreateMsg( + const std::string &_data, + const std::string &_type) const { - // Documentation inherited. - public: explicit SubscriptionHandler(const std::string &_nUuid, - const SubscribeOptions &_opts = SubscribeOptions()) - : ISubscriptionHandler(_nUuid, _opts) + std::shared_ptr msgPtr; + + const google::protobuf::Descriptor *desc = + google::protobuf::DescriptorPool::generated_pool() + ->FindMessageTypeByName(_type); + + // First, check if we have the descriptor from the generated proto + // classes. + if (desc) { + msgPtr.reset(google::protobuf::MessageFactory::generated_factory() + ->GetPrototype(desc)->New()); } - - // Documentation inherited. - public: const std::shared_ptr CreateMsg( - const std::string &_data, - const std::string &_type) const + else { - std::shared_ptr msgPtr; - - const google::protobuf::Descriptor *desc = - google::protobuf::DescriptorPool::generated_pool() - ->FindMessageTypeByName(_type); - - // First, check if we have the descriptor from the generated proto - // classes. - if (desc) - { - msgPtr.reset(google::protobuf::MessageFactory::generated_factory() - ->GetPrototype(desc)->New()); - } - else - { - // Fallback on Gazebo Msgs if the message type is not found. - msgPtr = gz::msgs::Factory::New(_type); - } - - if (!msgPtr) - return nullptr; - - // Create the message using some serialized data - if (!msgPtr->ParseFromString(_data)) - { - std::cerr << "CreateMsg() error: ParseFromString failed" << std::endl; - return nullptr; - } - - return msgPtr; + // Fallback on Gazebo Msgs if the message type is not found. + msgPtr = gz::msgs::Factory::New(_type); } - // Documentation inherited. - public: std::string TypeName() + if (!msgPtr) + return nullptr; + + // Create the message using some serialized data + if (!msgPtr->ParseFromString(_data)) { - return kGenericMessageType; + std::cerr << "CreateMsg() error: ParseFromString failed" << std::endl; + return nullptr; } - /// \brief Set the callback for this handler. - /// \param[in] _cb The callback. - public: void SetCallback(const MsgCallback &_cb) + return msgPtr; + } + + // Documentation inherited. + public: std::string TypeName() + { + return kGenericMessageType; + } + + /// \brief Set the callback for this handler. + /// \param[in] _cb The callback. + public: void SetCallback(const MsgCallback &_cb) + { + this->cb = _cb; + } + + // Documentation inherited. + public: bool RunLocalCallback(const ProtoMsg &_msg, + const MessageInfo &_info) + { + // No callback stored. + if (!this->cb) { - this->cb = _cb; + std::cerr << "SubscriptionHandler::RunLocalCallback() " + << "error: Callback is NULL" << std::endl; + return false; } - // Documentation inherited. - public: bool RunLocalCallback(const ProtoMsg &_msg, - const MessageInfo &_info) - { - // No callback stored. - if (!this->cb) - { - std::cerr << "SubscriptionHandler::RunLocalCallback() " - << "error: Callback is NULL" << std::endl; - return false; - } - - // Check the subscription throttling option. - if (!this->UpdateThrottling()) - return true; - - this->cb(_msg, _info); + // Check the subscription throttling option. + if (!this->UpdateThrottling()) return true; - } - /// \brief Callback to the function registered for this handler. - private: MsgCallback cb; - }; + this->cb(_msg, _info); + return true; + } + + /// \brief Callback to the function registered for this handler. + private: MsgCallback cb; + }; - ////////////////////////////////////////////////// - /// RawSubscriptionHandler is used to manage the callback of a raw - /// subscription. - class RawSubscriptionHandler : public SubscriptionHandlerBase - { - /// \brief Constructor - /// \param[in] _nUuid UUID of the node registering the handler - /// \param[in] _msgType Name of message type that this handler should - /// listen for. Setting this to kGenericMessageType will tell this handler - /// to listen for all message types. - /// \param[in] _opts Subscription options. - public: explicit RawSubscriptionHandler( - const std::string &_nUuid, - const std::string &_msgType = kGenericMessageType, - const SubscribeOptions &_opts = SubscribeOptions()); - - // Documentation inherited - public: std::string TypeName() override; - - /// \brief Set the callback of this handler. - /// \param[in] _callback The callback function that will be triggered when - /// a message is received. - public: void SetCallback(const RawCallback &_callback); - - /// \brief Executes the raw callback registered for this handler. - /// \param[in] _msgData Serialized string of message data - /// \param[in] _size Number of bytes in the serialized message data - /// \param[in] _info Meta-data for the message - /// \return True if the callback was triggered, false if the callback was - /// not set. - public: bool RunRawCallback(const char *_msgData, const size_t _size, - const MessageInfo &_info); - - /// \brief Destructor - public: ~RawSubscriptionHandler(); - - private: class Implementation; + ////////////////////////////////////////////////// + /// RawSubscriptionHandler is used to manage the callback of a raw + /// subscription. + class RawSubscriptionHandler : public SubscriptionHandlerBase + { + /// \brief Constructor + /// \param[in] _nUuid UUID of the node registering the handler + /// \param[in] _msgType Name of message type that this handler should + /// listen for. Setting this to kGenericMessageType will tell this handler + /// to listen for all message types. + /// \param[in] _opts Subscription options. + public: explicit RawSubscriptionHandler( + const std::string &_nUuid, + const std::string &_msgType = kGenericMessageType, + const SubscribeOptions &_opts = SubscribeOptions()); + + // Documentation inherited + public: std::string TypeName() override; + + /// \brief Set the callback of this handler. + /// \param[in] _callback The callback function that will be triggered when + /// a message is received. + public: void SetCallback(const RawCallback &_callback); + + /// \brief Executes the raw callback registered for this handler. + /// \param[in] _msgData Serialized string of message data + /// \param[in] _size Number of bytes in the serialized message data + /// \param[in] _info Meta-data for the message + /// \return True if the callback was triggered, false if the callback was + /// not set. + public: bool RunRawCallback(const char *_msgData, const size_t _size, + const MessageInfo &_info); + + /// \brief Destructor + public: ~RawSubscriptionHandler(); + + private: class Implementation; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -356,15 +354,13 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal - /// \brief Pointer to the implementation of the class - private: std::unique_ptr pimpl; + /// \internal + /// \brief Pointer to the implementation of the class + private: std::unique_ptr pimpl; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } -} - -#endif + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_SUBSCRIPTIONHANDLER_HH_ diff --git a/include/gz/transport/TopicStatistics.hh b/include/gz/transport/TopicStatistics.hh index 207004846..c7424bb7a 100644 --- a/include/gz/transport/TopicStatistics.hh +++ b/include/gz/transport/TopicStatistics.hh @@ -37,131 +37,128 @@ #include #endif -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + // Forward declarations. + class TopicStatisticsPrivate; + + /// \brief Computes the rolling average, min, max, and standard + /// deviation for a set of samples. + class GZ_TRANSPORT_VISIBLE Statistics { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - // Forward declarations. - class TopicStatisticsPrivate; - - /// \brief Computes the rolling average, min, max, and standard - /// deviation for a set of samples. - class GZ_TRANSPORT_VISIBLE Statistics - { - /// \brief Default constructor. - public: Statistics() = default; - - /// \brief Default destructor. - public: ~Statistics() = default; - - /// \brief Update with a new sample. - /// \param[in] _stat New statistic sample. - public: void Update(double _stat); - - /// \brief Get the average value. - /// \return the average value. - public: double Avg() const; - - /// \brief Get the standard deviation. - /// \return The standard deviation. - public: double StdDev() const; - - /// \brief Get the minimum sample value. - /// \return The minimum sample value. - public: double Min() const; - - /// \brief Get the maximum sample value. - /// \return The maximum sample value. - public: double Max() const; - - /// \brief Get the number of samples. - /// \return The number of samples. - public: uint64_t Count() const; - - /// \brief Count of the samples. - private: uint64_t count = 0; - - /// \brief Average value. - private: double average = 0; - - /// \brief Sum of the squared mean distance between samples. This is - /// used to calculate the standard deviation. - private: double sumSquareMeanDist = 0; - - /// \brief Minimum sample. - private: double min = std::numeric_limits::max(); - - /// \brief Maximum sample. - private: double max = std::numeric_limits::min(); - }; - - /// \brief Encapsulates statistics for a single topic. The set of - /// statistics include: - /// - /// 1. Number of dropped messages. - /// max time between publications. - /// 3. Receive statistics: The reception hz rate, standard - /// deviation between receiving messages, min time between receiving - /// messages, and max time between receiving messages. - /// - /// Publication statistics utilize time stamps generated by the - /// publisher. Receive statistics use time stamps generated by the - /// subscriber. - class GZ_TRANSPORT_VISIBLE TopicStatistics - { - /// \brief Default constructor. - public: TopicStatistics(); - - /// \brief Copy constructor. - /// \param[in] _stats Statistics to copy. - public: TopicStatistics(const TopicStatistics &_stats); - - /// \brief Default destructor. - public: ~TopicStatistics(); - - /// \brief Update the topic statistics. - /// \param[in] _sender Address of the sender. - /// \param[in] _stamp Publication time stamp. - /// \param[in] _seq Publication sequence number. - public: void Update(const std::string &_sender, - uint64_t _stamp, uint64_t _seq); - - /// \brief Populate a gz::msgs::Metric message with topic - /// statistics. - /// \param[in] _msg Message to populate. - public: void FillMessage(msgs::Metric &_msg) const; - - /// \brief Get the number of dropped messages. - /// \return Number of dropped messages. - public: uint64_t DroppedMsgCount() const; - - /// \brief Get statistics about publication of messages. - /// \return Publication statistics. - public: Statistics PublicationStatistics() const; - - /// \brief Get the statistics about reception of messages. - /// \return Reception statistics. - public: Statistics ReceptionStatistics() const; - - /// \brief Get the message age statistics. - /// \return Age statistics. - public: Statistics AgeStatistics() const; + /// \brief Default constructor. + public: Statistics() = default; + + /// \brief Default destructor. + public: ~Statistics() = default; + + /// \brief Update with a new sample. + /// \param[in] _stat New statistic sample. + public: void Update(double _stat); + + /// \brief Get the average value. + /// \return the average value. + public: double Avg() const; + + /// \brief Get the standard deviation. + /// \return The standard deviation. + public: double StdDev() const; + + /// \brief Get the minimum sample value. + /// \return The minimum sample value. + public: double Min() const; + + /// \brief Get the maximum sample value. + /// \return The maximum sample value. + public: double Max() const; + + /// \brief Get the number of samples. + /// \return The number of samples. + public: uint64_t Count() const; + + /// \brief Count of the samples. + private: uint64_t count = 0; + + /// \brief Average value. + private: double average = 0; + + /// \brief Sum of the squared mean distance between samples. This is + /// used to calculate the standard deviation. + private: double sumSquareMeanDist = 0; + + /// \brief Minimum sample. + private: double min = std::numeric_limits::max(); + + /// \brief Maximum sample. + private: double max = std::numeric_limits::min(); + }; + + /// \brief Encapsulates statistics for a single topic. The set of + /// statistics include: + /// + /// 1. Number of dropped messages. + /// max time between publications. + /// 3. Receive statistics: The reception hz rate, standard + /// deviation between receiving messages, min time between receiving + /// messages, and max time between receiving messages. + /// + /// Publication statistics utilize time stamps generated by the + /// publisher. Receive statistics use time stamps generated by the + /// subscriber. + class GZ_TRANSPORT_VISIBLE TopicStatistics + { + /// \brief Default constructor. + public: TopicStatistics(); + + /// \brief Copy constructor. + /// \param[in] _stats Statistics to copy. + public: TopicStatistics(const TopicStatistics &_stats); + + /// \brief Default destructor. + public: ~TopicStatistics(); + + /// \brief Update the topic statistics. + /// \param[in] _sender Address of the sender. + /// \param[in] _stamp Publication time stamp. + /// \param[in] _seq Publication sequence number. + public: void Update(const std::string &_sender, + uint64_t _stamp, uint64_t _seq); + + /// \brief Populate a gz::msgs::Metric message with topic + /// statistics. + /// \param[in] _msg Message to populate. + public: void FillMessage(msgs::Metric &_msg) const; + + /// \brief Get the number of dropped messages. + /// \return Number of dropped messages. + public: uint64_t DroppedMsgCount() const; + + /// \brief Get statistics about publication of messages. + /// \return Publication statistics. + public: Statistics PublicationStatistics() const; + + /// \brief Get the statistics about reception of messages. + /// \return Reception statistics. + public: Statistics ReceptionStatistics() const; + + /// \brief Get the message age statistics. + /// \return Age statistics. + public: Statistics AgeStatistics() const; #ifdef _WIN32 // Disable warning C4251 which is triggered by // std::unique_ptr #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Private data pointer. - private: std::unique_ptr dataPtr; + /// \brief Private data pointer. + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } -} -#endif + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_TOPICSTATISTICS_HH_ diff --git a/include/gz/transport/TopicStorage.hh b/include/gz/transport/TopicStorage.hh index 8cdfa557e..b2c20efc0 100644 --- a/include/gz/transport/TopicStorage.hh +++ b/include/gz/transport/TopicStorage.hh @@ -28,353 +28,349 @@ #include "gz/transport/Publisher.hh" #include "gz/transport/TransportTypes.hh" -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \class TopicStorage TopicStorage.hh gz/transport/TopicStorage.hh + /// \brief Store address information about topics and provide convenient + /// methods for adding new topics, removing them, etc. + template class TopicStorage { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \class TopicStorage TopicStorage.hh gz/transport/TopicStorage.hh - /// \brief Store address information about topics and provide convenient - /// methods for adding new topics, removing them, etc. - template class TopicStorage - { - /// \brief Constructor. - public: TopicStorage() = default; + /// \brief Constructor. + public: TopicStorage() = default; - /// \brief Destructor. - public: virtual ~TopicStorage() = default; + /// \brief Destructor. + public: virtual ~TopicStorage() = default; - /// \brief Add a new address associated to a given topic and node UUID. - /// \param[in] _publisher New publisher. - /// \return true if the new entry is added or false if not (because it - /// was already stored). - public: bool AddPublisher(const T &_publisher) + /// \brief Add a new address associated to a given topic and node UUID. + /// \param[in] _publisher New publisher. + /// \return true if the new entry is added or false if not (because it + /// was already stored). + public: bool AddPublisher(const T &_publisher) + { + // The topic does not exist. + if (this->data.find(_publisher.Topic()) == this->data.end()) { - // The topic does not exist. - if (this->data.find(_publisher.Topic()) == this->data.end()) - { - // VS2013 is buggy with initializer list here {} - this->data[_publisher.Topic()] = - std::map>(); - } - - // Check if the process uuid exists. - auto &m = this->data[_publisher.Topic()]; - if (m.find(_publisher.PUuid()) != m.end()) - { - // Check that the Publisher does not exist. - auto &v = m[_publisher.PUuid()]; - auto found = std::find_if(v.begin(), v.end(), - [&](const T &_pub) - { - return _pub.Addr() == _publisher.Addr() && - _pub.NUuid() == _publisher.NUuid(); - }); - - // The publisher was already existing, just exit. - if (found != v.end()) - return false; - } - - // Add a new Publisher entry. - m[_publisher.PUuid()].push_back(T(_publisher)); - return true; + // VS2013 is buggy with initializer list here {} + this->data[_publisher.Topic()] = + std::map>(); } - /// \brief Return if there is any publisher stored for the given topic. - /// \param[in] _topic Topic name. - /// \return True if there is at least one entry stored for the topic. - public: bool HasTopic(const std::string &_topic) const + // Check if the process uuid exists. + auto &m = this->data[_publisher.Topic()]; + if (m.find(_publisher.PUuid()) != m.end()) { - return this->data.find(_topic) != this->data.end(); - } + // Check that the Publisher does not exist. + auto &v = m[_publisher.PUuid()]; + auto found = std::find_if(v.begin(), v.end(), + [&](const T &_pub) + { + return _pub.Addr() == _publisher.Addr() && + _pub.NUuid() == _publisher.NUuid(); + }); - /// \brief Return if there is any publisher stored for the given topic and - /// type. - /// \param[in] _topic Topic name. - /// \param[in] _type Topic type. - /// \return True if there is at least one entry stored for the topic and - /// type. - public: bool HasTopic(const std::string &_topic, - const std::string &_type) const - { - if (!this->HasTopic(_topic)) + // The publisher was already existing, just exit. + if (found != v.end()) return false; + } - // m is {pUUID=>std::vector}. - auto &m = this->data.at(_topic); - - for (auto const &procs : m) - { - // Vector of publishers for a given topic and pUuid. - auto &v = procs.second; - auto found = std::find_if(v.begin(), v.end(), - [&](const T &_pub) - { - return _pub.MsgTypeName() == _type || - _pub.MsgTypeName() == kGenericMessageType; - }); + // Add a new Publisher entry. + m[_publisher.PUuid()].push_back(T(_publisher)); + return true; + } - // Type found! - if (found != v.end()) - return true; - } + /// \brief Return if there is any publisher stored for the given topic. + /// \param[in] _topic Topic name. + /// \return True if there is at least one entry stored for the topic. + public: bool HasTopic(const std::string &_topic) const + { + return this->data.find(_topic) != this->data.end(); + } + /// \brief Return if there is any publisher stored for the given topic and + /// type. + /// \param[in] _topic Topic name. + /// \param[in] _type Topic type. + /// \return True if there is at least one entry stored for the topic and + /// type. + public: bool HasTopic(const std::string &_topic, + const std::string &_type) const + { + if (!this->HasTopic(_topic)) return false; - } - /// \brief Return if there is any publisher stored for the given topic and - /// process UUID. - /// \param[in] _topic Topic name. - /// \param[in] _pUuid Process UUID of the publisher. - /// \return True if there is at least one address stored for the topic and - /// process UUID. - public: bool HasAnyPublishers(const std::string &_topic, - const std::string &_pUuid) const + // m is {pUUID=>std::vector}. + auto &m = this->data.at(_topic); + + for (auto const &procs : m) { - if (!this->HasTopic(_topic)) - return false; + // Vector of publishers for a given topic and pUuid. + auto &v = procs.second; + auto found = std::find_if(v.begin(), v.end(), + [&](const T &_pub) + { + return _pub.MsgTypeName() == _type || + _pub.MsgTypeName() == kGenericMessageType; + }); - return this->data.at(_topic).find(_pUuid) != - this->data.at(_topic).end(); + // Type found! + if (found != v.end()) + return true; } - /// \brief Return if the requested publisher's address is stored. - /// \param[in] _addr Publisher's address requested - /// \return true if the publisher's address is stored. - public: bool HasPublisher(const std::string &_addr) const + return false; + } + + /// \brief Return if there is any publisher stored for the given topic and + /// process UUID. + /// \param[in] _topic Topic name. + /// \param[in] _pUuid Process UUID of the publisher. + /// \return True if there is at least one address stored for the topic and + /// process UUID. + public: bool HasAnyPublishers(const std::string &_topic, + const std::string &_pUuid) const + { + if (!this->HasTopic(_topic)) + return false; + + return this->data.at(_topic).find(_pUuid) != + this->data.at(_topic).end(); + } + + /// \brief Return if the requested publisher's address is stored. + /// \param[in] _addr Publisher's address requested + /// \return true if the publisher's address is stored. + public: bool HasPublisher(const std::string &_addr) const + { + for (auto const &topic : this->data) { - for (auto const &topic : this->data) + for (auto const &proc : topic.second) { - for (auto const &proc : topic.second) + for (auto const &pub : proc.second) { - for (auto const &pub : proc.second) - { - if (pub.Addr() == _addr) - return true; - } + if (pub.Addr() == _addr) + return true; } } - return false; } + return false; + } - /// \brief Get the address information for a given topic and node UUID. - /// \param[in] _topic Topic name. - /// \param[in] _pUuid Process UUID of the publisher. - /// \param[in] _nUuid Node UUID of the publisher. - /// \param[out] _publisher Publisher's information requested. - /// \return true if a publisher is found for the given topic and UUID pair - public: bool Publisher(const std::string &_topic, - const std::string &_pUuid, - const std::string &_nUuid, - T &_publisher) const - { - // Topic not found. - if (this->data.find(_topic) == this->data.end()) - return false; - - // m is {pUUID=>Publisher}. - auto &m = this->data.at(_topic); + /// \brief Get the address information for a given topic and node UUID. + /// \param[in] _topic Topic name. + /// \param[in] _pUuid Process UUID of the publisher. + /// \param[in] _nUuid Node UUID of the publisher. + /// \param[out] _publisher Publisher's information requested. + /// \return true if a publisher is found for the given topic and UUID pair + public: bool Publisher(const std::string &_topic, + const std::string &_pUuid, + const std::string &_nUuid, + T &_publisher) const + { + // Topic not found. + if (this->data.find(_topic) == this->data.end()) + return false; - // pUuid not found. - if (m.find(_pUuid) == m.end()) - return false; + // m is {pUUID=>Publisher}. + auto &m = this->data.at(_topic); - // Vector of 0MQ known addresses for a given topic and pUuid. - auto &v = m.at(_pUuid); - auto found = std::find_if(v.begin(), v.end(), - [&](const T &_pub) - { - return _pub.NUuid() == _nUuid; - }); - // Address found! - if (found != v.end()) - { - _publisher = *found; - return true; - } - - // nUuid not found. + // pUuid not found. + if (m.find(_pUuid) == m.end()) return false; - } - /// \brief Get the map of publishers stored for a given topic. - /// \param[in] _topic Topic name. - /// \param[out] _info Map of publishers requested. - /// \return true if at least there is one publisher stored. - public: bool Publishers(const std::string &_topic, - std::map> &_info) const + // Vector of 0MQ known addresses for a given topic and pUuid. + auto &v = m.at(_pUuid); + auto found = std::find_if(v.begin(), v.end(), + [&](const T &_pub) + { + return _pub.NUuid() == _nUuid; + }); + // Address found! + if (found != v.end()) { - if (!this->HasTopic(_topic)) - return false; - - _info = this->data.at(_topic); + _publisher = *found; return true; } - /// \brief Remove a publisher associated to a given topic and UUID pair. - /// \param[in] _topic Topic name - /// \param[in] _pUuid Process UUID of the publisher. - /// \param[in] _nUuid Node UUID of the publisher. - /// \return True when the publisher was removed or false otherwise. - public: bool DelPublisherByNode(const std::string &_topic, - const std::string &_pUuid, - const std::string &_nUuid) - { - size_t counter = 0; + // nUuid not found. + return false; + } - // Iterate over all the topics. - if (this->data.find(_topic) != this->data.end()) - { - // m is {pUUID=>Publisher}. - auto &m = this->data[_topic]; + /// \brief Get the map of publishers stored for a given topic. + /// \param[in] _topic Topic name. + /// \param[out] _info Map of publishers requested. + /// \return true if at least there is one publisher stored. + public: bool Publishers(const std::string &_topic, + std::map> &_info) const + { + if (!this->HasTopic(_topic)) + return false; - // The pUuid exists. - if (m.find(_pUuid) != m.end()) - { - // Vector of 0MQ known addresses for a given topic and pUuid. - auto &v = m[_pUuid]; - auto priorSize = v.size(); - v.erase(std::remove_if(v.begin(), v.end(), - [&](const T &_pub) - { - return _pub.NUuid() == _nUuid; - }), - v.end()); - counter = priorSize - v.size(); - - if (v.empty()) - m.erase(_pUuid); - - if (m.empty()) - this->data.erase(_topic); - } - } + _info = this->data.at(_topic); + return true; + } - return counter > 0; - } + /// \brief Remove a publisher associated to a given topic and UUID pair. + /// \param[in] _topic Topic name + /// \param[in] _pUuid Process UUID of the publisher. + /// \param[in] _nUuid Node UUID of the publisher. + /// \return True when the publisher was removed or false otherwise. + public: bool DelPublisherByNode(const std::string &_topic, + const std::string &_pUuid, + const std::string &_nUuid) + { + size_t counter = 0; - /// \brief Remove all the publishers associated to a given process. - /// \param[in] _pUuid Process' UUID of the publisher. - /// \return True when at least one address was removed or false otherwise. - public: bool DelPublishersByProc(const std::string &_pUuid) + // Iterate over all the topics. + if (this->data.find(_topic) != this->data.end()) { - size_t counter = 0; + // m is {pUUID=>Publisher}. + auto &m = this->data[_topic]; - // Iterate over all the topics. - for (auto it = this->data.begin(); it != this->data.end();) + // The pUuid exists. + if (m.find(_pUuid) != m.end()) { - // m is {pUUID=>Publisher}. - auto &m = it->second; - counter += m.erase(_pUuid); + // Vector of 0MQ known addresses for a given topic and pUuid. + auto &v = m[_pUuid]; + auto priorSize = v.size(); + v.erase(std::remove_if(v.begin(), v.end(), + [&](const T &_pub) + { + return _pub.NUuid() == _nUuid; + }), + v.end()); + counter = priorSize - v.size(); + + if (v.empty()) + m.erase(_pUuid); + if (m.empty()) - this->data.erase(it++); - else - ++it; + this->data.erase(_topic); } - - return counter > 0; } - /// \brief Given a process UUID, the function returns the list of - /// publishers contained in this process UUID with its address information - /// \param[in] _pUuid Process UUID. - /// \param[out] _pubs Map of publishers where the keys are the node UUIDs - /// and the value is its address information. - public: void PublishersByProc(const std::string &_pUuid, - std::map> &_pubs) const + return counter > 0; + } + + /// \brief Remove all the publishers associated to a given process. + /// \param[in] _pUuid Process' UUID of the publisher. + /// \return True when at least one address was removed or false otherwise. + public: bool DelPublishersByProc(const std::string &_pUuid) + { + size_t counter = 0; + + // Iterate over all the topics. + for (auto it = this->data.begin(); it != this->data.end();) { - _pubs.clear(); + // m is {pUUID=>Publisher}. + auto &m = it->second; + counter += m.erase(_pUuid); + if (m.empty()) + this->data.erase(it++); + else + ++it; + } + + return counter > 0; + } + + /// \brief Given a process UUID, the function returns the list of + /// publishers contained in this process UUID with its address information + /// \param[in] _pUuid Process UUID. + /// \param[out] _pubs Map of publishers where the keys are the node UUIDs + /// and the value is its address information. + public: void PublishersByProc(const std::string &_pUuid, + std::map> &_pubs) const + { + _pubs.clear(); - // Iterate over all the topics. - for (auto const &topic : this->data) + // Iterate over all the topics. + for (auto const &topic : this->data) + { + // m is {pUUID=>Publisher}. + auto &m = topic.second; + if (m.find(_pUuid) != m.end()) { - // m is {pUUID=>Publisher}. - auto &m = topic.second; - if (m.find(_pUuid) != m.end()) + auto &v = m.at(_pUuid); + for (auto const &pub : v) { - auto &v = m.at(_pUuid); - for (auto const &pub : v) - { - _pubs[pub.NUuid()].push_back(T(pub)); - } + _pubs[pub.NUuid()].push_back(T(pub)); } } } + } - /// \brief Given a process UUID and the node UUID, the function returns - /// the list of publishers contained in the node. - /// \param[in] _pUuid Process UUID. - /// \param[in] _nUuid Node UUID. - /// \param[out] _pubs Vector of publishers. - public: void PublishersByNode(const std::string &_pUuid, - const std::string &_nUuid, - std::vector &_pubs) const - { - _pubs.clear(); + /// \brief Given a process UUID and the node UUID, the function returns + /// the list of publishers contained in the node. + /// \param[in] _pUuid Process UUID. + /// \param[in] _nUuid Node UUID. + /// \param[out] _pubs Vector of publishers. + public: void PublishersByNode(const std::string &_pUuid, + const std::string &_nUuid, + std::vector &_pubs) const + { + _pubs.clear(); - // Iterate over all the topics. - for (auto const &topic : this->data) + // Iterate over all the topics. + for (auto const &topic : this->data) + { + // m is {pUUID=>Publisher}. + auto const &m = topic.second; + if (m.find(_pUuid) != m.end()) { - // m is {pUUID=>Publisher}. - auto const &m = topic.second; - if (m.find(_pUuid) != m.end()) + auto const &v = m.at(_pUuid); + for (auto const &pub : v) { - auto const &v = m.at(_pUuid); - for (auto const &pub : v) + if (pub.NUuid() == _nUuid) { - if (pub.NUuid() == _nUuid) - { - _pubs.push_back(T(pub)); - } + _pubs.push_back(T(pub)); } } } } + } - /// \brief Get the list of topics currently stored. - /// \param[out] _topics List of stored topics. - public: void TopicList(std::vector &_topics) const - { - for (auto const &topic : this->data) - _topics.push_back(topic.first); - } + /// \brief Get the list of topics currently stored. + /// \param[out] _topics List of stored topics. + public: void TopicList(std::vector &_topics) const + { + for (auto const &topic : this->data) + _topics.push_back(topic.first); + } - /// \brief Print all the information for debugging purposes. - public: void Print() const + /// \brief Print all the information for debugging purposes. + public: void Print() const + { + std::cout << "---" << std::endl; + for (auto const &topic : this->data) { - std::cout << "---" << std::endl; - for (auto const &topic : this->data) + std::cout << "[" << topic.first << "]" << std::endl; + auto &m = topic.second; + for (auto const &proc : m) { - std::cout << "[" << topic.first << "]" << std::endl; - auto &m = topic.second; - for (auto const &proc : m) + std::cout << "\tProc. UUID: " << proc.first << std::endl; + auto &v = proc.second; + for (auto const &publisher : v) { - std::cout << "\tProc. UUID: " << proc.first << std::endl; - auto &v = proc.second; - for (auto const &publisher : v) - { - std::cout << publisher; - } + std::cout << publisher; } } } + } - /// \brief Clear the content. - public: void Clear() - { - this->data.clear(); - } - - /// \brief The keys are topics. The values are another map, where the key - /// is the process UUID and the value a vector of publishers. - private: std::map>> data; - }; + /// \brief Clear the content. + public: void Clear() + { + this->data.clear(); } - } -} -#endif + /// \brief The keys are topics. The values are another map, where the key + /// is the process UUID and the value a vector of publishers. + private: std::map>> data; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_TOPICSTORAGE_HH_ diff --git a/include/gz/transport/TopicUtils.hh b/include/gz/transport/TopicUtils.hh index 10c3e63f4..cf7e54380 100644 --- a/include/gz/transport/TopicUtils.hh +++ b/include/gz/transport/TopicUtils.hh @@ -24,126 +24,122 @@ #include "gz/transport/config.hh" #include "gz/transport/Export.hh" -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \class TopicUtils TopicUtils.hh gz/transport/TopicUtils.hh + /// \brief This class provides different utilities related with topics. + class GZ_TRANSPORT_VISIBLE TopicUtils { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \class TopicUtils TopicUtils.hh gz/transport/TopicUtils.hh - /// \brief This class provides different utilities related with topics. - class GZ_TRANSPORT_VISIBLE TopicUtils - { - /// \brief Determines if a namespace is valid. A namespace's length must - /// not exceed kMaxNameLength. - /// The following symbols are not allowed as part of the - /// namespace: '@', ':=', '~'. - /// \param[in] _ns Namespace to be checked. - /// \return true if the namespace is valid. - public: static bool IsValidNamespace(const std::string &_ns); + /// \brief Determines if a namespace is valid. A namespace's length must + /// not exceed kMaxNameLength. + /// The following symbols are not allowed as part of the + /// namespace: '@', ':=', '~'. + /// \param[in] _ns Namespace to be checked. + /// \return true if the namespace is valid. + public: static bool IsValidNamespace(const std::string &_ns); - /// \brief Determines if a partition is valid. - /// The same rules to validate a topic name applies to a partition with - /// the addition of the empty string, which is a valid partition (meaning - /// no partition is used). A partition name's length must not exceed - /// kMaxNameLength. - /// \param[in] _partition Partition to be checked. - /// \return true if the partition is valid. - public: static bool IsValidPartition(const std::string &_partition); + /// \brief Determines if a partition is valid. + /// The same rules to validate a topic name applies to a partition with + /// the addition of the empty string, which is a valid partition (meaning + /// no partition is used). A partition name's length must not exceed + /// kMaxNameLength. + /// \param[in] _partition Partition to be checked. + /// \return true if the partition is valid. + public: static bool IsValidPartition(const std::string &_partition); - /// \brief Determines if a topic name is valid. A topic name is any - /// non-empty alphanumeric string. The symbol '/' is also allowed as part - /// of a topic name. - /// The following symbols are not allowed as part of the - /// topic name: '@', ':=', '~'. - /// A topic name's length must not exceed kMaxNameLength. - /// Examples of valid topics: abc, /abc, /abc/de, /abc/de/ - /// \param[in] _topic Topic name to be checked. - /// \return true if the topic name is valid. - public: static bool IsValidTopic(const std::string &_topic); + /// \brief Determines if a topic name is valid. A topic name is any + /// non-empty alphanumeric string. The symbol '/' is also allowed as part + /// of a topic name. + /// The following symbols are not allowed as part of the + /// topic name: '@', ':=', '~'. + /// A topic name's length must not exceed kMaxNameLength. + /// Examples of valid topics: abc, /abc, /abc/de, /abc/de/ + /// \param[in] _topic Topic name to be checked. + /// \return true if the topic name is valid. + public: static bool IsValidTopic(const std::string &_topic); - /// \brief Get the full topic path given a namespace and a topic name. - /// A fully qualified topic name's length must not exceed kMaxNameLength. - /// The fully qualified name follows the next syntax: - /// \@\\@\/\ - /// where: - /// \: The name of the partition or empty string. - /// A "/" will be prefixed to the partition name unless is - /// empty or it already starts with slash. A trailing slash - /// will always be removed. - /// \: The namespace or empty string. A namespace is a prefix - /// applied to the topic name. If not empty, it will always - /// start with a "/". A trailing slash will always be - /// removed - /// \: The topic name. A trailing slash will always be removed. - /// - /// Note: Intuitively, you can imagine the fully qualified name as a - /// UNIX absolute path, where the partition is always sorrounded by "@". - /// A namespace, if present, corresponds with the directories of the - /// path, and you can imagine the topic as the filename. - /// - /// E.g.: - /// Only topic: @@/topic - /// No partition: @@/namespace/topic1 - /// No namespace: @/partition@/topic1 - /// Partition+namespace+topic: @/my_partition@/name/space/topic - /// - /// \param[in] _partition Partition name. - /// \param[in] _ns Namespace. - /// \param[in] _topic Topic name. - /// \param[out] _name Fully qualified topic name. - /// \return True if the fully qualified name is valid - /// (if partition, namespace and topic are correct). - /// \sa IsValidPartition - /// \sa IsValidNamespace - /// \sa IsValidTopic - /// \sa DecomposeFullyQualifiedTopic - public: static bool FullyQualifiedName(const std::string &_partition, - const std::string &_ns, - const std::string &_topic, - std::string &_name); + /// \brief Get the full topic path given a namespace and a topic name. + /// A fully qualified topic name's length must not exceed kMaxNameLength. + /// The fully qualified name follows the next syntax: + /// \@\\@\/\ + /// where: + /// \: The name of the partition or empty string. + /// A "/" will be prefixed to the partition name unless is + /// empty or it already starts with slash. A trailing slash + /// will always be removed. + /// \: The namespace or empty string. A namespace is a prefix + /// applied to the topic name. If not empty, it will always + /// start with a "/". A trailing slash will always be + /// removed + /// \: The topic name. A trailing slash will always be removed. + /// + /// Note: Intuitively, you can imagine the fully qualified name as a + /// UNIX absolute path, where the partition is always sorrounded by "@". + /// A namespace, if present, corresponds with the directories of the + /// path, and you can imagine the topic as the filename. + /// + /// E.g.: + /// Only topic: @@/topic + /// No partition: @@/namespace/topic1 + /// No namespace: @/partition@/topic1 + /// Partition+namespace+topic: @/my_partition@/name/space/topic + /// + /// \param[in] _partition Partition name. + /// \param[in] _ns Namespace. + /// \param[in] _topic Topic name. + /// \param[out] _name Fully qualified topic name. + /// \return True if the fully qualified name is valid + /// (if partition, namespace and topic are correct). + /// \sa IsValidPartition + /// \sa IsValidNamespace + /// \sa IsValidTopic + /// \sa DecomposeFullyQualifiedTopic + public: static bool FullyQualifiedName(const std::string &_partition, + const std::string &_ns, + const std::string &_topic, + std::string &_name); - /// \brief Decompose a fully qualified topic name into its partition and - /// topic strings. Note that if the topic is preceded by a namespace, then - /// the namespace and topic name will remain together as one string. - /// - /// Given a fully qualified topic name with the following syntax: - /// - /// \@\\@\/\ - /// - /// The _partition output argument will be set to \, and the - /// _namespaceAndTopic output argument will be set to - /// \/\. - /// - /// \param[in] _fullyQualifiedName The fully qualified topic name. - /// \param[out] _partition The partition component of the fully qualified - /// topic name. - /// \param[out] _namespaceAndTopic The namespace and topic name component. - /// Note that there is no way to distinguish between where a namespace - /// ends and a topic name begins, since topic names may contain slashes. - /// \return True if the topic and partition were set. - /// \sa FullyQualifiedName - public: static bool DecomposeFullyQualifiedTopic( - const std::string &_fullyQualifiedName, - std::string &_partition, - std::string &_namespaceAndTopic); + /// \brief Decompose a fully qualified topic name into its partition and + /// topic strings. Note that if the topic is preceded by a namespace, then + /// the namespace and topic name will remain together as one string. + /// + /// Given a fully qualified topic name with the following syntax: + /// + /// \@\\@\/\ + /// + /// The _partition output argument will be set to \, and the + /// _namespaceAndTopic output argument will be set to + /// \/\. + /// + /// \param[in] _fullyQualifiedName The fully qualified topic name. + /// \param[out] _partition The partition component of the fully qualified + /// topic name. + /// \param[out] _namespaceAndTopic The namespace and topic name component. + /// Note that there is no way to distinguish between where a namespace + /// ends and a topic name begins, since topic names may contain slashes. + /// \return True if the topic and partition were set. + /// \sa FullyQualifiedName + public: static bool DecomposeFullyQualifiedTopic( + const std::string &_fullyQualifiedName, + std::string &_partition, + std::string &_namespaceAndTopic); - /// \brief Convert a topic name to a valid topic. The input topic is - /// modified by: - /// * turning white space into `_`. - /// * removing special characters and combinations. - /// \param[in] _topic Input topic, which may be invalid. - /// \return A valid topic, or empty string if not possible to convert. - public: static std::string AsValidTopic(const std::string &_topic); + /// \brief Convert a topic name to a valid topic. The input topic is + /// modified by: + /// * turning white space into `_`. + /// * removing special characters and combinations. + /// \param[in] _topic Input topic, which may be invalid. + /// \return A valid topic, or empty string if not possible to convert. + public: static std::string AsValidTopic(const std::string &_topic); - /// \brief The kMaxNameLength specifies the maximum number of characters - /// allowed in a namespace, a partition name, a topic name, and a fully - /// qualified topic name. - public: static const uint16_t kMaxNameLength = 65535; - }; - } - } -} - -#endif + /// \brief The kMaxNameLength specifies the maximum number of characters + /// allowed in a namespace, a partition name, a topic name, and a fully + /// qualified topic name. + public: static const uint16_t kMaxNameLength = 65535; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_TOPICUTILS_HH_ diff --git a/include/gz/transport/TransportTypes.hh b/include/gz/transport/TransportTypes.hh index 59c7350cd..f002f0387 100644 --- a/include/gz/transport/TransportTypes.hh +++ b/include/gz/transport/TransportTypes.hh @@ -36,152 +36,149 @@ #include "gz/transport/config.hh" #include "gz/transport/Publisher.hh" -namespace gz +namespace gz::transport { - namespace transport - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \brief Forward declarations. - class IRepHandler; - class IReqHandler; - class ISubscriptionHandler; - class RawSubscriptionHandler; - class MessageInfo; - - /// \def Addresses_M - /// \brief Map that stores all generic publishers. - /// The keys are the process uuids of the nodes. For each uuid key, the - /// value contains the list of publishers advertising the topic within the - /// same proccess uuid. - template - using Addresses_M = std::map>; - - /// \def MsgAddresses_M - /// \brief Specialized Addresses_M map for message publishers. - using MsgAddresses_M = Addresses_M; - - /// \def SrvAddresses_M - /// \brief Specialized Addresses_M map for service publishers. - using SrvAddresses_M = Addresses_M; - - /// \def ProtoMsg - /// \brief An abbreviated protobuf message type. - using ProtoMsg = google::protobuf::Message; - - /// \def ProtoMsgPtr - /// \brief Shared pointer to any protobuf message. - using ProtoMsgPtr = std::shared_ptr; - - /// \def ISubscriptionHandlerPtr - /// \brief Shared pointer to ISubscriptionHandler. - using ISubscriptionHandlerPtr = std::shared_ptr; - - /// \def RawSubscriptionHandlerPtr - /// \brief Shared pointer to RawSubscriptionHandler - using RawSubscriptionHandlerPtr = std::shared_ptr; - - /// \def ISubscriptionHandler_M - /// \brief Map to store the different subscription handlers for a topic. - /// Each node can have its own subscription handler. The node id - /// is used as key and a pointer to a generic subscription handler is the - /// value. - using ISubscriptionHandler_M = - std::map; - - /// \def RawSubscriptionHandler_M - /// \brief Map to store the raw subscription handlers for a topic. - /// Each node can have its own raw subscription handler. The node id is used - /// as the key and a pointer to a raw subscription handler is the value. - using RawSubscriptionHandler_M = - std::map; - - /// \def IRepHandlerPtr - /// \brief Shared pointer to IRepHandler. - using IRepHandlerPtr = std::shared_ptr; - - /// \def IReqHandlerPtr - /// \brief Shared pointer to IReqHandler. - using IReqHandlerPtr = std::shared_ptr; - - /// \def IReqHandler_M - /// \brief Map to store the different service request handlers for a - /// topic. Each node can have its own request handler. The node id - /// is used as key. The value is another map, where the key is the request - /// UUID and the value is pointer to a generic request handler. - using IReqHandler_M = - std::map>; - - /// \def DiscoveryCallback - /// \brief The user can register callbacks of this type when new connections - /// or disconnections are detected by the discovery. The prototype of the - /// callback contains the publisher's information advertising a topic. - /// E.g.: void onDiscoveryResponse(const MessagePublisher &_publisher). - template - using DiscoveryCallback = std::function; - - /// \def MsgDiscoveryCallback - /// \brief Specialized DiscoveryCallback function for receiving a message - /// publisher. - using MsgDiscoveryCallback = - std::function; - - /// \def SrvDiscoveryCallback - /// \brief Specialized DiscoveryCallback function for receiving a service - /// publisher. - using SrvDiscoveryCallback = - std::function; - - /// \def MsgCallback - /// \brief User callback used for receiving messages: - /// \param[in] _msg Protobuf message containing the topic update. - /// \param[in] _info Message information (e.g.: topic name). - template - using MsgCallback = - std::function; - - /// \def RawCallback - /// \brief User callback used for receiving raw message data: - /// \param[in] _msgData string of a serialized protobuf message - /// \param[in] _size Number of bytes in the serialized message data - /// string. - /// \param[in] _info Message information - using RawCallback = - std::function; - - /// \def Timestamp - /// \brief Used to evaluate the validity of a discovery entry. - using Timestamp = std::chrono::steady_clock::time_point; - - /// \def DeallocFunc - /// \brief Used when passing data to be published using ZMQ. - /// \param[in] _data The buffer containing the message to be published. - /// \param[in] _hint This parameter can be used if more complex allocation - /// mechanism is used. Say we allocated the chunk using some "allocator" - /// object and we have to deallocate it via the same object. - /// In such case we can pass the pointer to allocator as a hint to - /// zmq::message_t and modify the deallocation function as follows: - /// - /// void my_free (void *data, void *hint) - /// { - /// ((allocator_t*) hint)->free (data); - /// } - /// \ref http://zeromq.org/blog:zero-copy - using DeallocFunc = void(void *_data, void *_hint); - - /// \brief The string type used for generic messages. - const std::string kGenericMessageType = "google.protobuf.Message"; - - /// \brief The high water mark of the recieve message buffer. - /// \sa NodeShared::RcvHwm - const int kDefaultRcvHwm = 1000; - - /// \brief The high water mark of the send message buffer. - /// \sa NodeShared::SndHwm - const int kDefaultSndHwm = 1000; - } - } -} -#endif + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \brief Forward declarations. + class IRepHandler; + class IReqHandler; + class ISubscriptionHandler; + class RawSubscriptionHandler; + class MessageInfo; + + /// \def Addresses_M + /// \brief Map that stores all generic publishers. + /// The keys are the process uuids of the nodes. For each uuid key, the + /// value contains the list of publishers advertising the topic within the + /// same proccess uuid. + template + using Addresses_M = std::map>; + + /// \def MsgAddresses_M + /// \brief Specialized Addresses_M map for message publishers. + using MsgAddresses_M = Addresses_M; + + /// \def SrvAddresses_M + /// \brief Specialized Addresses_M map for service publishers. + using SrvAddresses_M = Addresses_M; + + /// \def ProtoMsg + /// \brief An abbreviated protobuf message type. + using ProtoMsg = google::protobuf::Message; + + /// \def ProtoMsgPtr + /// \brief Shared pointer to any protobuf message. + using ProtoMsgPtr = std::shared_ptr; + + /// \def ISubscriptionHandlerPtr + /// \brief Shared pointer to ISubscriptionHandler. + using ISubscriptionHandlerPtr = std::shared_ptr; + + /// \def RawSubscriptionHandlerPtr + /// \brief Shared pointer to RawSubscriptionHandler + using RawSubscriptionHandlerPtr = std::shared_ptr; + + /// \def ISubscriptionHandler_M + /// \brief Map to store the different subscription handlers for a topic. + /// Each node can have its own subscription handler. The node id + /// is used as key and a pointer to a generic subscription handler is the + /// value. + using ISubscriptionHandler_M = + std::map; + + /// \def RawSubscriptionHandler_M + /// \brief Map to store the raw subscription handlers for a topic. + /// Each node can have its own raw subscription handler. The node id is used + /// as the key and a pointer to a raw subscription handler is the value. + using RawSubscriptionHandler_M = + std::map; + + /// \def IRepHandlerPtr + /// \brief Shared pointer to IRepHandler. + using IRepHandlerPtr = std::shared_ptr; + + /// \def IReqHandlerPtr + /// \brief Shared pointer to IReqHandler. + using IReqHandlerPtr = std::shared_ptr; + + /// \def IReqHandler_M + /// \brief Map to store the different service request handlers for a + /// topic. Each node can have its own request handler. The node id + /// is used as key. The value is another map, where the key is the request + /// UUID and the value is pointer to a generic request handler. + using IReqHandler_M = + std::map>; + + /// \def DiscoveryCallback + /// \brief The user can register callbacks of this type when new connections + /// or disconnections are detected by the discovery. The prototype of the + /// callback contains the publisher's information advertising a topic. + /// E.g.: void onDiscoveryResponse(const MessagePublisher &_publisher). + template + using DiscoveryCallback = std::function; + + /// \def MsgDiscoveryCallback + /// \brief Specialized DiscoveryCallback function for receiving a message + /// publisher. + using MsgDiscoveryCallback = + std::function; + + /// \def SrvDiscoveryCallback + /// \brief Specialized DiscoveryCallback function for receiving a service + /// publisher. + using SrvDiscoveryCallback = + std::function; + + /// \def MsgCallback + /// \brief User callback used for receiving messages: + /// \param[in] _msg Protobuf message containing the topic update. + /// \param[in] _info Message information (e.g.: topic name). + template + using MsgCallback = + std::function; + + /// \def RawCallback + /// \brief User callback used for receiving raw message data: + /// \param[in] _msgData string of a serialized protobuf message + /// \param[in] _size Number of bytes in the serialized message data + /// string. + /// \param[in] _info Message information + using RawCallback = + std::function; + + /// \def Timestamp + /// \brief Used to evaluate the validity of a discovery entry. + using Timestamp = std::chrono::steady_clock::time_point; + + /// \def DeallocFunc + /// \brief Used when passing data to be published using ZMQ. + /// \param[in] _data The buffer containing the message to be published. + /// \param[in] _hint This parameter can be used if more complex allocation + /// mechanism is used. Say we allocated the chunk using some "allocator" + /// object and we have to deallocate it via the same object. + /// In such case we can pass the pointer to allocator as a hint to + /// zmq::message_t and modify the deallocation function as follows: + /// + /// void my_free (void *data, void *hint) + /// { + /// ((allocator_t*) hint)->free (data); + /// } + /// \ref http://zeromq.org/blog:zero-copy + using DeallocFunc = void(void *_data, void *_hint); + + /// \brief The string type used for generic messages. + const std::string kGenericMessageType = "google.protobuf.Message"; + + /// \brief The high water mark of the recieve message buffer. + /// \sa NodeShared::RcvHwm + const int kDefaultRcvHwm = 1000; + + /// \brief The high water mark of the send message buffer. + /// \sa NodeShared::SndHwm + const int kDefaultSndHwm = 1000; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_TRANSPORTTYPES_HH_ diff --git a/include/gz/transport/Uuid.hh b/include/gz/transport/Uuid.hh index 42001f751..d45cf97c1 100644 --- a/include/gz/transport/Uuid.hh +++ b/include/gz/transport/Uuid.hh @@ -33,49 +33,46 @@ using portable_uuid_t = uuid_t; #endif -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \class Uuid Uuid.hh gz/transport/Uuid.hh + /// \brief A portable class for representing a Universally Unique Identifier + class GZ_TRANSPORT_VISIBLE Uuid { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \class Uuid Uuid.hh gz/transport/Uuid.hh - /// \brief A portable class for representing a Universally Unique Identifier - class GZ_TRANSPORT_VISIBLE Uuid - { - /// \brief Constructor. - public: Uuid(); + /// \brief Constructor. + public: Uuid(); - /// \brief Destructor. - public: virtual ~Uuid(); + /// \brief Destructor. + public: virtual ~Uuid(); - /// \brief Return the string representation of the Uuid. - /// \return the UUID in string format. - public: std::string ToString() const; + /// \brief Return the string representation of the Uuid. + /// \return the UUID in string format. + public: std::string ToString() const; - /// \brief Stream insertion operator. - /// \param[out] _out The output stream. - /// \param[in] _uuid UUID to write to the stream. - public: friend std::ostream &operator<<(std::ostream &_out, - const gz::transport::Uuid &_uuid) - { - _out << _uuid.ToString(); - return _out; - } + /// \brief Stream insertion operator. + /// \param[out] _out The output stream. + /// \param[in] _uuid UUID to write to the stream. + public: friend std::ostream &operator<<(std::ostream &_out, + const gz::transport::Uuid &_uuid) + { + _out << _uuid.ToString(); + return _out; + } - /// \brief Length of a UUID in string format. - /// A UUID is a 16-octet number. In its string representation, every octet - /// is divided in two parts, and each part (4 bits) is represented as an - /// hexadecimal value. A UUID is also displayed in five groups separated - /// by hyphens, in the form 8-4-4-4-12 for a total of 36 characters. - /// To summarize: 36 octets + \0 = 37 octets. - private: static const int UuidStrLen = 37; + /// \brief Length of a UUID in string format. + /// A UUID is a 16-octet number. In its string representation, every octet + /// is divided in two parts, and each part (4 bits) is represented as an + /// hexadecimal value. A UUID is also displayed in five groups separated + /// by hyphens, in the form 8-4-4-4-12 for a total of 36 characters. + /// To summarize: 36 octets + \0 = 37 octets. + private: static const int UuidStrLen = 37; - /// \brief Internal representation. - private: portable_uuid_t data; - }; - } - } -} -#endif + /// \brief Internal representation. + private: portable_uuid_t data; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_UUID_HH diff --git a/include/gz/transport/detail/Node.hh b/include/gz/transport/detail/Node.hh index d069ebdbe..4692bfd07 100644 --- a/include/gz/transport/detail/Node.hh +++ b/include/gz/transport/detail/Node.hh @@ -24,539 +24,428 @@ #include #include -namespace gz +namespace gz::transport { - namespace transport + ////////////////////////////////////////////////// + template + Node::Publisher Node::Advertise( + const std::string &_topic, + const AdvertiseMessageOptions &_options) { - ////////////////////////////////////////////////// - template - Node::Publisher Node::Advertise( - const std::string &_topic, - const AdvertiseMessageOptions &_options) - { - return this->Advertise(_topic, MessageT().GetTypeName(), _options); - } - - ////////////////////////////////////////////////// - template - bool Node::Subscribe( - const std::string &_topic, - void(*_cb)(const MessageT &_msg), - const SubscribeOptions &_opts) - { - std::function f = - [_cb](const MessageT & _internalMsg, - const MessageInfo &/*_internalInfo*/) - { - (*_cb)(_internalMsg); - }; - - return this->Subscribe(_topic, f, _opts); - } + return this->Advertise(_topic, MessageT().GetTypeName(), _options); + } - ////////////////////////////////////////////////// - template - bool Node::Subscribe( - const std::string &_topic, - std::function _cb, - const SubscribeOptions &_opts) + ////////////////////////////////////////////////// + template + bool Node::Subscribe( + const std::string &_topic, + void(*_cb)(const MessageT &_msg), + const SubscribeOptions &_opts) + { + std::function f = + [_cb](const MessageT & _internalMsg, + const MessageInfo &/*_internalInfo*/) { - std::function f = - [cb = std::move(_cb)](const MessageT & _internalMsg, - const MessageInfo &/*_internalInfo*/) - { - cb(_internalMsg); - }; + (*_cb)(_internalMsg); + }; - return this->Subscribe(_topic, f, _opts); - } + return this->Subscribe(_topic, f, _opts); + } - ////////////////////////////////////////////////// - template - bool Node::Subscribe( - const std::string &_topic, - void(ClassT::*_cb)(const MessageT &_msg), - ClassT *_obj, - const SubscribeOptions &_opts) + ////////////////////////////////////////////////// + template + bool Node::Subscribe( + const std::string &_topic, + std::function _cb, + const SubscribeOptions &_opts) + { + std::function f = + [cb = std::move(_cb)](const MessageT & _internalMsg, + const MessageInfo &/*_internalInfo*/) { - std::function f = - [_cb, _obj](const MessageT & _internalMsg, - const MessageInfo &/*_internalInfo*/) - { - auto cb = std::bind(_cb, _obj, std::placeholders::_1); - cb(_internalMsg); - }; + cb(_internalMsg); + }; - return this->Subscribe(_topic, f, _opts); - } + return this->Subscribe(_topic, f, _opts); + } - ////////////////////////////////////////////////// - template - bool Node::Subscribe( - const std::string &_topic, - void(*_cb)(const MessageT &_msg, const MessageInfo &_info), - const SubscribeOptions &_opts) + ////////////////////////////////////////////////// + template + bool Node::Subscribe( + const std::string &_topic, + void(ClassT::*_cb)(const MessageT &_msg), + ClassT *_obj, + const SubscribeOptions &_opts) + { + std::function f = + [_cb, _obj](const MessageT & _internalMsg, + const MessageInfo &/*_internalInfo*/) { - std::function f = - [_cb](const MessageT & _internalMsg, - const MessageInfo &_internalInfo) - { - (*_cb)(_internalMsg, _internalInfo); - }; + auto cb = std::bind(_cb, _obj, std::placeholders::_1); + cb(_internalMsg); + }; - return this->Subscribe(_topic, f, _opts); - } + return this->Subscribe(_topic, f, _opts); + } - ////////////////////////////////////////////////// - template - bool Node::Subscribe( - const std::string &_topic, - std::function _cb, - const SubscribeOptions &_opts) + ////////////////////////////////////////////////// + template + bool Node::Subscribe( + const std::string &_topic, + void(*_cb)(const MessageT &_msg, const MessageInfo &_info), + const SubscribeOptions &_opts) + { + std::function f = + [_cb](const MessageT & _internalMsg, + const MessageInfo &_internalInfo) { - // Topic remapping. - std::string topic = _topic; - this->Options().TopicRemap(_topic, topic); + (*_cb)(_internalMsg, _internalInfo); + }; - std::string fullyQualifiedTopic; - if (!TopicUtils::FullyQualifiedName(this->Options().Partition(), - this->Options().NameSpace(), topic, fullyQualifiedTopic)) - { - std::cerr << "Topic [" << topic << "] is not valid." << std::endl; - return false; - } + return this->Subscribe(_topic, f, _opts); + } - // Create a new subscription handler. - std::shared_ptr> subscrHandlerPtr( - new SubscriptionHandler(this->NodeUuid(), _opts)); + ////////////////////////////////////////////////// + template + bool Node::Subscribe( + const std::string &_topic, + std::function _cb, + const SubscribeOptions &_opts) + { + // Topic remapping. + std::string topic = _topic; + this->Options().TopicRemap(_topic, topic); - // Insert the callback into the handler. - subscrHandlerPtr->SetCallback(std::move(_cb)); + std::string fullyQualifiedTopic; + if (!TopicUtils::FullyQualifiedName(this->Options().Partition(), + this->Options().NameSpace(), topic, fullyQualifiedTopic)) + { + std::cerr << "Topic [" << topic << "] is not valid." << std::endl; + return false; + } - std::lock_guard lk(this->Shared()->mutex); + // Create a new subscription handler. + std::shared_ptr> subscrHandlerPtr( + new SubscriptionHandler(this->NodeUuid(), _opts)); - // Store the subscription handler. Each subscription handler is - // associated with a topic. When the receiving thread gets new data, - // it will recover the subscription handler associated to the topic and - // will invoke the callback. - this->Shared()->localSubscribers.normal.AddHandler( - fullyQualifiedTopic, this->NodeUuid(), subscrHandlerPtr); + // Insert the callback into the handler. + subscrHandlerPtr->SetCallback(std::move(_cb)); - return this->SubscribeHelper(fullyQualifiedTopic); - } + std::lock_guard lk(this->Shared()->mutex); - ////////////////////////////////////////////////// - template - bool Node::Subscribe( - const std::string &_topic, - void(ClassT::*_cb)(const MessageT &_msg, const MessageInfo &_info), - ClassT *_obj, - const SubscribeOptions &_opts) - { - std::function f = - [_cb, _obj](const MessageT & _internalMsg, - const MessageInfo &_internalInfo) - { - auto cb = std::bind(_cb, _obj, std::placeholders::_1, - std::placeholders::_2); - cb(_internalMsg, _internalInfo); - }; + // Store the subscription handler. Each subscription handler is + // associated with a topic. When the receiving thread gets new data, + // it will recover the subscription handler associated to the topic and + // will invoke the callback. + this->Shared()->localSubscribers.normal.AddHandler( + fullyQualifiedTopic, this->NodeUuid(), subscrHandlerPtr); - return this->Subscribe(_topic, f, _opts); - } + return this->SubscribeHelper(fullyQualifiedTopic); + } - ////////////////////////////////////////////////// - template - bool Node::Advertise( + ////////////////////////////////////////////////// + template + bool Node::Subscribe( const std::string &_topic, - bool(*_cb)(const RequestT &_request, ReplyT &_reply), - const AdvertiseServiceOptions &_options) + void(ClassT::*_cb)(const MessageT &_msg, const MessageInfo &_info), + ClassT *_obj, + const SubscribeOptions &_opts) + { + std::function f = + [_cb, _obj](const MessageT & _internalMsg, + const MessageInfo &_internalInfo) { - // Dev Note: This overload of Advertise(~) is necessary so that the - // compiler can correctly infer the template arguments. We cannot rely - // on the compiler to implicitly cast the function pointer to a - // std::function object, because the compiler cannot infer the template - // parameters T1 and T2 from the signature of the function pointer that - // gets passed to Advertise(~). - - // We create a std::function object so that we can explicitly call the - // baseline overload of Advertise(~). - std::function f = - [_cb](const RequestT &_internalReq, ReplyT &_internalRep) - { - return (*_cb)(_internalReq, _internalRep); - }; + auto cb = std::bind(_cb, _obj, std::placeholders::_1, + std::placeholders::_2); + cb(_internalMsg, _internalInfo); + }; - return this->Advertise(_topic, f, _options); - } + return this->Subscribe(_topic, f, _opts); + } - ////////////////////////////////////////////////// - template - bool Node::Advertise( - const std::string &_topic, - bool(*_cb)(ReplyT &_reply), - const AdvertiseServiceOptions &_options) + ////////////////////////////////////////////////// + template + bool Node::Advertise( + const std::string &_topic, + bool(*_cb)(const RequestT &_request, ReplyT &_reply), + const AdvertiseServiceOptions &_options) + { + // Dev Note: This overload of Advertise(~) is necessary so that the + // compiler can correctly infer the template arguments. We cannot rely + // on the compiler to implicitly cast the function pointer to a + // std::function object, because the compiler cannot infer the template + // parameters T1 and T2 from the signature of the function pointer that + // gets passed to Advertise(~). + + // We create a std::function object so that we can explicitly call the + // baseline overload of Advertise(~). + std::function f = + [_cb](const RequestT &_internalReq, ReplyT &_internalRep) { - std::function f = - [_cb](const msgs::Empty &/*_internalReq*/, ReplyT &_internalRep) - { - return (*_cb)(_internalRep); - }; - return this->Advertise(_topic, f, _options); - } + return (*_cb)(_internalReq, _internalRep); + }; - ////////////////////////////////////////////////// - template - bool Node::Advertise( - const std::string &_topic, - void(*_cb)(const RequestT &_request), - const AdvertiseServiceOptions &_options) - { - std::function f = - [_cb](const RequestT &_internalReq, - gz::msgs::Empty &/*_internalRep*/) - { - (*_cb)(_internalReq); - return true; - }; + return this->Advertise(_topic, f, _options); + } - return this->Advertise(_topic, f, _options); - } + ////////////////////////////////////////////////// + template + bool Node::Advertise( + const std::string &_topic, + bool(*_cb)(ReplyT &_reply), + const AdvertiseServiceOptions &_options) + { + std::function f = + [_cb](const msgs::Empty &/*_internalReq*/, ReplyT &_internalRep) + { + return (*_cb)(_internalRep); + }; + return this->Advertise(_topic, f, _options); + } - ////////////////////////////////////////////////// - template - bool Node::Advertise( - const std::string &_topic, - std::function _cb, - const AdvertiseServiceOptions &_options) + ////////////////////////////////////////////////// + template + bool Node::Advertise( + const std::string &_topic, + void(*_cb)(const RequestT &_request), + const AdvertiseServiceOptions &_options) + { + std::function f = + [_cb](const RequestT &_internalReq, + gz::msgs::Empty &/*_internalRep*/) { - // Topic remapping. - std::string topic = _topic; - this->Options().TopicRemap(_topic, topic); + (*_cb)(_internalReq); + return true; + }; - std::string fullyQualifiedTopic; - if (!TopicUtils::FullyQualifiedName(this->Options().Partition(), - this->Options().NameSpace(), topic, fullyQualifiedTopic)) - { - std::cerr << "Service [" << topic << "] is not valid." << std::endl; - return false; - } + return this->Advertise(_topic, f, _options); + } - // Create a new service reply handler. - std::shared_ptr> repHandlerPtr( - new RepHandler()); + ////////////////////////////////////////////////// + template + bool Node::Advertise( + const std::string &_topic, + std::function _cb, + const AdvertiseServiceOptions &_options) + { + // Topic remapping. + std::string topic = _topic; + this->Options().TopicRemap(_topic, topic); - // Insert the callback into the handler. - repHandlerPtr->SetCallback(_cb); + std::string fullyQualifiedTopic; + if (!TopicUtils::FullyQualifiedName(this->Options().Partition(), + this->Options().NameSpace(), topic, fullyQualifiedTopic)) + { + std::cerr << "Service [" << topic << "] is not valid." << std::endl; + return false; + } - std::lock_guard lk(this->Shared()->mutex); + // Create a new service reply handler. + std::shared_ptr> repHandlerPtr( + new RepHandler()); - // Add the topic to the list of advertised services. - this->SrvsAdvertised().insert(fullyQualifiedTopic); + // Insert the callback into the handler. + repHandlerPtr->SetCallback(_cb); - // Store the replier handler. Each replier handler is - // associated with a topic. When the receiving thread gets new requests, - // it will recover the replier handler associated to the topic and - // will invoke the service call. - this->Shared()->repliers.AddHandler( - fullyQualifiedTopic, this->NodeUuid(), repHandlerPtr); + std::lock_guard lk(this->Shared()->mutex); - // Notify the discovery service to register and advertise my responser. - ServicePublisher publisher(fullyQualifiedTopic, - this->Shared()->myReplierAddress, - this->Shared()->replierId.ToString(), - this->Shared()->pUuid, this->NodeUuid(), - RequestT().GetTypeName(), ReplyT().GetTypeName(), _options); + // Add the topic to the list of advertised services. + this->SrvsAdvertised().insert(fullyQualifiedTopic); - if (!this->Shared()->AdvertisePublisher(publisher)) - { - std::cerr << "Node::Advertise(): Error advertising service [" - << topic - << "]. Did you forget to start the discovery service?" - << std::endl; - return false; - } + // Store the replier handler. Each replier handler is + // associated with a topic. When the receiving thread gets new requests, + // it will recover the replier handler associated to the topic and + // will invoke the service call. + this->Shared()->repliers.AddHandler( + fullyQualifiedTopic, this->NodeUuid(), repHandlerPtr); - return true; - } + // Notify the discovery service to register and advertise my responser. + ServicePublisher publisher(fullyQualifiedTopic, + this->Shared()->myReplierAddress, + this->Shared()->replierId.ToString(), + this->Shared()->pUuid, this->NodeUuid(), + RequestT().GetTypeName(), ReplyT().GetTypeName(), _options); - ////////////////////////////////////////////////// - template - bool Node::Advertise( - const std::string &_topic, - std::function &_cb, - const AdvertiseServiceOptions &_options) + if (!this->Shared()->AdvertisePublisher(publisher)) { - std::function f = - [_cb](const msgs::Empty &/*_internalReq*/, ReplyT &_internalRep) - { - return (_cb)(_internalRep); - }; - return this->Advertise(_topic, f, _options); + std::cerr << "Node::Advertise(): Error advertising service [" + << topic + << "]. Did you forget to start the discovery service?" + << std::endl; + return false; } - ////////////////////////////////////////////////// - template - bool Node::Advertise( - const std::string &_topic, - std::function &_cb, - const AdvertiseServiceOptions &_options) - { - std::function f = - [_cb](const RequestT &_internalReq, - gz::msgs::Empty &/*_internalRep*/) - { - (_cb)(_internalReq); - return true; - }; - - return this->Advertise(_topic, f, _options); - } + return true; + } - ////////////////////////////////////////////////// - template - bool Node::Advertise( - const std::string &_topic, - bool(ClassT::*_cb)(const RequestT &_request, ReplyT &_reply), - ClassT *_obj, - const AdvertiseServiceOptions &_options) + ////////////////////////////////////////////////// + template + bool Node::Advertise( + const std::string &_topic, + std::function &_cb, + const AdvertiseServiceOptions &_options) + { + std::function f = + [_cb](const msgs::Empty &/*_internalReq*/, ReplyT &_internalRep) { - std::function f = - [_cb, _obj](const RequestT &_internalReq, - ReplyT &_internalRep) - { - return (_obj->*_cb)(_internalReq, _internalRep); - }; - - return this->Advertise(_topic, f, _options); - } + return (_cb)(_internalRep); + }; + return this->Advertise(_topic, f, _options); + } - ////////////////////////////////////////////////// - template - bool Node::Advertise( - const std::string &_topic, - bool(ClassT::*_cb)(ReplyT &_reply), - ClassT *_obj, - const AdvertiseServiceOptions &_options) + ////////////////////////////////////////////////// + template + bool Node::Advertise( + const std::string &_topic, + std::function &_cb, + const AdvertiseServiceOptions &_options) + { + std::function f = + [_cb](const RequestT &_internalReq, + gz::msgs::Empty &/*_internalRep*/) { - std::function f = - [_cb, _obj](const msgs::Empty &/*_internalReq*/, ReplyT &_internalRep) - { - return (_obj->*_cb)(_internalRep); - }; + (_cb)(_internalReq); + return true; + }; - return this->Advertise(_topic, f, _options); - } + return this->Advertise(_topic, f, _options); + } - ////////////////////////////////////////////////// - template - bool Node::Advertise( - const std::string &_topic, - void(ClassT::*_cb)(const RequestT &_request), - ClassT *_obj, - const AdvertiseServiceOptions &_options) + ////////////////////////////////////////////////// + template + bool Node::Advertise( + const std::string &_topic, + bool(ClassT::*_cb)(const RequestT &_request, ReplyT &_reply), + ClassT *_obj, + const AdvertiseServiceOptions &_options) + { + std::function f = + [_cb, _obj](const RequestT &_internalReq, + ReplyT &_internalRep) { - std::function f = - [_cb, _obj](const RequestT &_internalReq, - gz::msgs::Empty &/*_internalRep*/) - { - auto cb = std::bind(_cb, _obj, std::placeholders::_1); - cb(_internalReq); - return true; - }; + return (_obj->*_cb)(_internalReq, _internalRep); + }; - return this->Advertise(_topic, f, _options); - } + return this->Advertise(_topic, f, _options); + } - ////////////////////////////////////////////////// - template - bool Node::Request( - const std::string &_topic, - const RequestT &_request, - void(*_cb)(const ReplyT &_reply, const bool _result)) + ////////////////////////////////////////////////// + template + bool Node::Advertise( + const std::string &_topic, + bool(ClassT::*_cb)(ReplyT &_reply), + ClassT *_obj, + const AdvertiseServiceOptions &_options) + { + std::function f = + [_cb, _obj](const msgs::Empty &/*_internalReq*/, ReplyT &_internalRep) { - std::function f = - [_cb](const ReplyT &_internalRep, const bool _internalResult) - { - (*_cb)(_internalRep, _internalResult); - }; - - return this->Request(_topic, _request, f); - } + return (_obj->*_cb)(_internalRep); + }; - ////////////////////////////////////////////////// - template - bool Node::Request( - const std::string &_topic, - void(*_cb)(const ReplyT &_reply, const bool _result)) - { - msgs::Empty req; - return this->Request(_topic, req, _cb); - } + return this->Advertise(_topic, f, _options); + } - ////////////////////////////////////////////////// - template - bool Node::Request( - const std::string &_topic, - const RequestT &_request, - std::function &_cb) + ////////////////////////////////////////////////// + template + bool Node::Advertise( + const std::string &_topic, + void(ClassT::*_cb)(const RequestT &_request), + ClassT *_obj, + const AdvertiseServiceOptions &_options) + { + std::function f = + [_cb, _obj](const RequestT &_internalReq, + gz::msgs::Empty &/*_internalRep*/) { - // Topic remapping. - std::string topic = _topic; - this->Options().TopicRemap(_topic, topic); - - std::string fullyQualifiedTopic; - if (!TopicUtils::FullyQualifiedName(this->Options().Partition(), - this->Options().NameSpace(), topic, fullyQualifiedTopic)) - { - std::cerr << "Service [" << topic << "] is not valid." << std::endl; - return false; - } - - bool localResponserFound; - IRepHandlerPtr repHandler; - { - std::lock_guard lk(this->Shared()->mutex); - localResponserFound = this->Shared()->repliers.FirstHandler( - fullyQualifiedTopic, - RequestT().GetTypeName(), - ReplyT().GetTypeName(), - repHandler); - } - - // If the responser is within my process. - if (localResponserFound) - { - // There is a responser in my process, let's use it. - ReplyT rep; - bool result = repHandler->RunLocalCallback(_request, rep); - - _cb(rep, result); - return true; - } - - // Create a new request handler. - std::shared_ptr> reqHandlerPtr( - new ReqHandler(this->NodeUuid())); - - // Insert the request's parameters. - reqHandlerPtr->SetMessage(&_request); - - // Insert the callback into the handler. - reqHandlerPtr->SetCallback(_cb); + auto cb = std::bind(_cb, _obj, std::placeholders::_1); + cb(_internalReq); + return true; + }; - { - std::lock_guard lk(this->Shared()->mutex); + return this->Advertise(_topic, f, _options); + } - // Store the request handler. - this->Shared()->requests.AddHandler( - fullyQualifiedTopic, this->NodeUuid(), reqHandlerPtr); + ////////////////////////////////////////////////// + template + bool Node::Request( + const std::string &_topic, + const RequestT &_request, + void(*_cb)(const ReplyT &_reply, const bool _result)) + { + std::function f = + [_cb](const ReplyT &_internalRep, const bool _internalResult) + { + (*_cb)(_internalRep, _internalResult); + }; - // If the responser's address is known, make the request. - SrvAddresses_M addresses; - if (this->Shared()->TopicPublishers(fullyQualifiedTopic, addresses)) - { - this->Shared()->SendPendingRemoteReqs(fullyQualifiedTopic, - RequestT().GetTypeName(), ReplyT().GetTypeName()); - } - else - { - // Discover the service responser. - if (!this->Shared()->DiscoverService(fullyQualifiedTopic)) - { - std::cerr << "Node::Request(): Error discovering service [" - << topic - << "]. Did you forget to start the discovery service?" - << std::endl; - return false; - } - } - } + return this->Request(_topic, _request, f); + } - return true; - } + ////////////////////////////////////////////////// + template + bool Node::Request( + const std::string &_topic, + void(*_cb)(const ReplyT &_reply, const bool _result)) + { + msgs::Empty req; + return this->Request(_topic, req, _cb); + } - ////////////////////////////////////////////////// - template - bool Node::Request( - const std::string &_topic, - std::function &_cb) - { - msgs::Empty req; - return this->Request(_topic, req, _cb); - } + ////////////////////////////////////////////////// + template + bool Node::Request( + const std::string &_topic, + const RequestT &_request, + std::function &_cb) + { + // Topic remapping. + std::string topic = _topic; + this->Options().TopicRemap(_topic, topic); - ////////////////////////////////////////////////// - template - bool Node::Request( - const std::string &_topic, - const RequestT &_request, - void(ClassT::*_cb)(const ReplyT &_reply, const bool _result), - ClassT *_obj) + std::string fullyQualifiedTopic; + if (!TopicUtils::FullyQualifiedName(this->Options().Partition(), + this->Options().NameSpace(), topic, fullyQualifiedTopic)) { - std::function f = - [_cb, _obj](const ReplyT &_internalRep, const bool _internalResult) - { - auto cb = std::bind(_cb, _obj, std::placeholders::_1, - std::placeholders::_2); - cb(_internalRep, _internalResult); - }; - - return this->Request(_topic, _request, f); + std::cerr << "Service [" << topic << "] is not valid." << std::endl; + return false; } - ////////////////////////////////////////////////// - template - bool Node::Request( - const std::string &_topic, - void(ClassT::*_cb)(const ReplyT &_reply, const bool _result), - ClassT *_obj) + bool localResponserFound; + IRepHandlerPtr repHandler; { - msgs::Empty req; - return this->Request(_topic, req, _cb, _obj); + std::lock_guard lk(this->Shared()->mutex); + localResponserFound = this->Shared()->repliers.FirstHandler( + fullyQualifiedTopic, + RequestT().GetTypeName(), + ReplyT().GetTypeName(), + repHandler); } - ////////////////////////////////////////////////// - template - bool Node::Request( - const std::string &_topic, - const RequestT &_request, - const unsigned int &_timeout, - ReplyT &_reply, - bool &_result) + // If the responser is within my process. + if (localResponserFound) { - // Topic remapping. - std::string topic = _topic; - this->Options().TopicRemap(_topic, topic); + // There is a responser in my process, let's use it. + ReplyT rep; + bool result = repHandler->RunLocalCallback(_request, rep); - std::string fullyQualifiedTopic; - if (!TopicUtils::FullyQualifiedName(this->Options().Partition(), - this->Options().NameSpace(), topic, fullyQualifiedTopic)) - { - std::cerr << "Service [" << topic << "] is not valid." << std::endl; - return false; - } + _cb(rep, result); + return true; + } - // Create a new request handler. - std::shared_ptr> reqHandlerPtr( - new ReqHandler(this->NodeUuid())); + // Create a new request handler. + std::shared_ptr> reqHandlerPtr( + new ReqHandler(this->NodeUuid())); - // Insert the request's parameters. - reqHandlerPtr->SetMessage(&_request); - reqHandlerPtr->SetResponse(&_reply); + // Insert the request's parameters. + reqHandlerPtr->SetMessage(&_request); - std::unique_lock lk(this->Shared()->mutex); + // Insert the callback into the handler. + reqHandlerPtr->SetCallback(_cb); - // If the responser is within my process. - IRepHandlerPtr repHandler; - if (this->Shared()->repliers.FirstHandler(fullyQualifiedTopic, - _request.GetTypeName(), _reply.GetTypeName(), repHandler)) - { - // There is a responser in my process, let's use it. - _result = repHandler->RunLocalCallback(_request, _reply); - return true; - } + { + std::lock_guard lk(this->Shared()->mutex); // Store the request handler. this->Shared()->requests.AddHandler( @@ -567,7 +456,7 @@ namespace gz if (this->Shared()->TopicPublishers(fullyQualifiedTopic, addresses)) { this->Shared()->SendPendingRemoteReqs(fullyQualifiedTopic, - _request.GetTypeName(), _reply.GetTypeName()); + RequestT().GetTypeName(), ReplyT().GetTypeName()); } else { @@ -581,63 +470,170 @@ namespace gz return false; } } + } - // Wait until the REP is available. - bool executed = reqHandlerPtr->WaitUntil(lk, _timeout); + return true; + } - // The request was not executed. - if (!executed) - return false; + ////////////////////////////////////////////////// + template + bool Node::Request( + const std::string &_topic, + std::function &_cb) + { + msgs::Empty req; + return this->Request(_topic, req, _cb); + } - // The request was executed but did not succeed. - if (!reqHandlerPtr->Result()) - { - _result = false; - return true; - } + ////////////////////////////////////////////////// + template + bool Node::Request( + const std::string &_topic, + const RequestT &_request, + void(ClassT::*_cb)(const ReplyT &_reply, const bool _result), + ClassT *_obj) + { + std::function f = + [_cb, _obj](const ReplyT &_internalRep, const bool _internalResult) + { + auto cb = std::bind(_cb, _obj, std::placeholders::_1, + std::placeholders::_2); + cb(_internalRep, _internalResult); + }; - // Parse the response. - if (!_reply.ParseFromString(reqHandlerPtr->Response())) + return this->Request(_topic, _request, f); + } + + ////////////////////////////////////////////////// + template + bool Node::Request( + const std::string &_topic, + void(ClassT::*_cb)(const ReplyT &_reply, const bool _result), + ClassT *_obj) + { + msgs::Empty req; + return this->Request(_topic, req, _cb, _obj); + } + + ////////////////////////////////////////////////// + template + bool Node::Request( + const std::string &_topic, + const RequestT &_request, + const unsigned int &_timeout, + ReplyT &_reply, + bool &_result) + { + // Topic remapping. + std::string topic = _topic; + this->Options().TopicRemap(_topic, topic); + + std::string fullyQualifiedTopic; + if (!TopicUtils::FullyQualifiedName(this->Options().Partition(), + this->Options().NameSpace(), topic, fullyQualifiedTopic)) + { + std::cerr << "Service [" << topic << "] is not valid." << std::endl; + return false; + } + + // Create a new request handler. + std::shared_ptr> reqHandlerPtr( + new ReqHandler(this->NodeUuid())); + + // Insert the request's parameters. + reqHandlerPtr->SetMessage(&_request); + reqHandlerPtr->SetResponse(&_reply); + + std::unique_lock lk(this->Shared()->mutex); + + // If the responser is within my process. + IRepHandlerPtr repHandler; + if (this->Shared()->repliers.FirstHandler(fullyQualifiedTopic, + _request.GetTypeName(), _reply.GetTypeName(), repHandler)) + { + // There is a responser in my process, let's use it. + _result = repHandler->RunLocalCallback(_request, _reply); + return true; + } + + // Store the request handler. + this->Shared()->requests.AddHandler( + fullyQualifiedTopic, this->NodeUuid(), reqHandlerPtr); + + // If the responser's address is known, make the request. + SrvAddresses_M addresses; + if (this->Shared()->TopicPublishers(fullyQualifiedTopic, addresses)) + { + this->Shared()->SendPendingRemoteReqs(fullyQualifiedTopic, + _request.GetTypeName(), _reply.GetTypeName()); + } + else + { + // Discover the service responser. + if (!this->Shared()->DiscoverService(fullyQualifiedTopic)) { - std::cerr << "Node::Request(): Error Parsing the response" + std::cerr << "Node::Request(): Error discovering service [" + << topic + << "]. Did you forget to start the discovery service?" << std::endl; - _result = false; - return true; + return false; } + } + + // Wait until the REP is available. + bool executed = reqHandlerPtr->WaitUntil(lk, _timeout); + + // The request was not executed. + if (!executed) + return false; - _result = true; + // The request was executed but did not succeed. + if (!reqHandlerPtr->Result()) + { + _result = false; return true; } - ////////////////////////////////////////////////// - template - bool Node::Request( - const std::string &_topic, - const unsigned int &_timeout, - ReplyT &_reply, - bool &_result) + // Parse the response. + if (!_reply.ParseFromString(reqHandlerPtr->Response())) { - msgs::Empty req; - return this->Request(_topic, req, _timeout, _reply, _result); + std::cerr << "Node::Request(): Error Parsing the response" + << std::endl; + _result = false; + return true; } - ////////////////////////////////////////////////// - template - bool Node::Request( - const std::string &_topic, - const RequestT &_request) - { - // This callback is here for reusing the regular Request() call with - // input and output parameters. - std::function f = - [](const gz::msgs::Empty &, const bool) - { - }; + _result = true; + return true; + } - return this->Request( - _topic, _request, f); - } + ////////////////////////////////////////////////// + template + bool Node::Request( + const std::string &_topic, + const unsigned int &_timeout, + ReplyT &_reply, + bool &_result) + { + msgs::Empty req; + return this->Request(_topic, req, _timeout, _reply, _result); } -} -#endif + ////////////////////////////////////////////////// + template + bool Node::Request( + const std::string &_topic, + const RequestT &_request) + { + // This callback is here for reusing the regular Request() call with + // input and output parameters. + std::function f = + [](const gz::msgs::Empty &, const bool) + { + }; + + return this->Request( + _topic, _request, f); + } +} // namespace gz::transport +#endif // GZ_TRANSPORT_DETAIL_NODE_HH_ diff --git a/log/include/gz/transport/log/Batch.hh b/log/include/gz/transport/log/Batch.hh index 8578e323d..28724f575 100644 --- a/log/include/gz/transport/log/Batch.hh +++ b/log/include/gz/transport/log/Batch.hh @@ -24,52 +24,48 @@ #include #include -namespace gz +namespace gz::transport::log { - namespace transport - { - namespace log - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \brief Forward declaration - class BatchPrivate; - class Log; + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \brief Forward declaration + class BatchPrivate; + class Log; - /// \brief Holds the result of a query for messages - class GZ_TRANSPORT_LOG_VISIBLE Batch - { - /// \brief Default constructor - public: Batch(); + /// \brief Holds the result of a query for messages + class GZ_TRANSPORT_LOG_VISIBLE Batch + { + /// \brief Default constructor + public: Batch(); - /// \brief move constructor - /// \param[in] _old the instance being moved into this one - public: Batch(Batch &&_old); // NOLINT + /// \brief move constructor + /// \param[in] _old the instance being moved into this one + public: Batch(Batch &&_old); // NOLINT - /// \brief Move assignement operator - /// \param[in] _other the new Batch replacing the current one - /// \return The updated Batch instance. - public: Batch& operator=(Batch &&_other); // NOLINT + /// \brief Move assignement operator + /// \param[in] _other the new Batch replacing the current one + /// \return The updated Batch instance. + public: Batch& operator=(Batch &&_other); // NOLINT - /// \brief destructor - public: ~Batch(); + /// \brief destructor + public: ~Batch(); - /// \brief typedef for prettiness - public: using iterator = MsgIter; + /// \brief typedef for prettiness + public: using iterator = MsgIter; - /// \brief Iterator to first message in batch - /// \remarks the lowercase function name is required to support - /// range-based for loops - /// \return an iterator to the start of the messages - public: iterator begin(); + /// \brief Iterator to first message in batch + /// \remarks the lowercase function name is required to support + /// range-based for loops + /// \return an iterator to the start of the messages + public: iterator begin(); - /// \brief Iterator to one past the last message in a batch - /// \remarks the lowercase function name is required to support - /// range-based for loops - /// \return an iterator that is not equal to any iterator that points - /// to a valid message - public: iterator end(); + /// \brief Iterator to one past the last message in a batch + /// \remarks the lowercase function name is required to support + /// range-based for loops + /// \return an iterator that is not equal to any iterator that points + /// to a valid message + public: iterator end(); #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -77,23 +73,21 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Private implementation - private: std::unique_ptr dataPtr; + /// \brief Private implementation + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - /// \brief Construct with private implementation - /// \param[in] _pimpl a private implementation pointer - /// \internal - private: Batch( - std::unique_ptr &&_pimpl); // NOLINT(build/c++11) + /// \brief Construct with private implementation + /// \param[in] _pimpl a private implementation pointer + /// \internal + private: Batch( + std::unique_ptr &&_pimpl); // NOLINT(build/c++11) - /// \brief Log can use private constructor - friend class Log; - }; - } - } - } -} -#endif + /// \brief Log can use private constructor + friend class Log; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::log +#endif // GZ_TRANSPORT_LOG_BATCH_HH_ diff --git a/log/include/gz/transport/log/Descriptor.hh b/log/include/gz/transport/log/Descriptor.hh index 36a272c1c..3ef311229 100644 --- a/log/include/gz/transport/log/Descriptor.hh +++ b/log/include/gz/transport/log/Descriptor.hh @@ -26,73 +26,69 @@ #include #include -namespace gz +namespace gz::transport::log { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + // Forward declaration + class Log; + + ////////////////////////////////////////////////// + /// \brief The Descriptor class provides meta-information about what a log + /// contains. This may be useful for determining QueryOptions or for + /// generating a high-level overview of a Log's contents. + class GZ_TRANSPORT_LOG_VISIBLE Descriptor { - namespace log - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - // Forward declaration - class Log; - - ////////////////////////////////////////////////// - /// \brief The Descriptor class provides meta-information about what a log - /// contains. This may be useful for determining QueryOptions or for - /// generating a high-level overview of a Log's contents. - class GZ_TRANSPORT_LOG_VISIBLE Descriptor - { - /// \brief A map from a name (e.g. topic name or message type name) to - /// the id of a row in one of the database tables. (name -> id) - public: using NameToId = std::map; - - /// \brief A map from a name to a map from a name to a row ID. - /// (name -> name -> id) - public: using NameToMap = std::map; - - /// \brief A topic in the database is uniquely identified by a pair of - /// (topic name, message type). - /// This function allows you to find the id of a topic by searching - /// (topic name -> message type name -> ID). - /// \return A map from topic names to a map of message types to row ids. - /// \sa MsgTypesToTopicsToId() - public: const NameToMap &TopicsToMsgTypesToId() const; - - /// \brief A topic in the database is uniquely identified by a pair of - /// (topic name, message type). - /// This function allows you to find the id of a topic by searching - /// (message type name -> topic name -> ID). - /// \return A map from message types to a map of topic names to row ids. - /// \sa TopicsToMsgTypesToId() - public: const NameToMap &MsgTypesToTopicsToId() const; - - /// \brief Convenience method to get an id given a topic name and type - /// \param[in] _topicName Name of the topic that you are interested in. - /// \param[in] _msgType Name of the message type that you are interested - /// in. - /// \return an id of a row in the topics table, or -1 none exists - public: int64_t TopicId( - const std::string &_topicName, - const std::string &_msgType) const; - - // The Log class is a friend so that it can construct a Descriptor - friend class Log; - - /// \brief Destructor - public: ~Descriptor(); - - /// \brief The Descriptor class must only be created by calling - /// \sa Log::Descriptor(). - private: Descriptor(); - - /// \brief Move constructor, not used by most - /// \internal - public: Descriptor(Descriptor &&_orig); // NOLINT - - /// \internal Implementation for this class - class Implementation; + /// \brief A map from a name (e.g. topic name or message type name) to + /// the id of a row in one of the database tables. (name -> id) + public: using NameToId = std::map; + + /// \brief A map from a name to a map from a name to a row ID. + /// (name -> name -> id) + public: using NameToMap = std::map; + + /// \brief A topic in the database is uniquely identified by a pair of + /// (topic name, message type). + /// This function allows you to find the id of a topic by searching + /// (topic name -> message type name -> ID). + /// \return A map from topic names to a map of message types to row ids. + /// \sa MsgTypesToTopicsToId() + public: const NameToMap &TopicsToMsgTypesToId() const; + + /// \brief A topic in the database is uniquely identified by a pair of + /// (topic name, message type). + /// This function allows you to find the id of a topic by searching + /// (message type name -> topic name -> ID). + /// \return A map from message types to a map of topic names to row ids. + /// \sa TopicsToMsgTypesToId() + public: const NameToMap &MsgTypesToTopicsToId() const; + + /// \brief Convenience method to get an id given a topic name and type + /// \param[in] _topicName Name of the topic that you are interested in. + /// \param[in] _msgType Name of the message type that you are interested + /// in. + /// \return an id of a row in the topics table, or -1 none exists + public: int64_t TopicId( + const std::string &_topicName, + const std::string &_msgType) const; + + // The Log class is a friend so that it can construct a Descriptor + friend class Log; + + /// \brief Destructor + public: ~Descriptor(); + + /// \brief The Descriptor class must only be created by calling + /// \sa Log::Descriptor(). + private: Descriptor(); + + /// \brief Move constructor, not used by most + /// \internal + public: Descriptor(Descriptor &&_orig); // NOLINT + + /// \internal Implementation for this class + class Implementation; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -100,15 +96,12 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal Pointer to implementation - private: std::unique_ptr dataPtr; + /// \internal Pointer to implementation + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } - } -} - -#endif + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::log +#endif // GZ_TRANSPORT_LOG_DESCRIPTOR_HH_ diff --git a/log/include/gz/transport/log/Log.hh b/log/include/gz/transport/log/Log.hh index c999e448a..0642cbfb2 100644 --- a/log/include/gz/transport/log/Log.hh +++ b/log/include/gz/transport/log/Log.hh @@ -29,95 +29,91 @@ #include #include -namespace gz +namespace gz::transport::log { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \brief Name of Environment variable containing path to schema + const std::string SchemaLocationEnvVar = "GZ_TRANSPORT_LOG_SQL_PATH"; + + /// \brief Interface to a log file + class GZ_TRANSPORT_LOG_VISIBLE Log { - namespace log - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \brief Name of Environment variable containing path to schema - const std::string SchemaLocationEnvVar = "GZ_TRANSPORT_LOG_SQL_PATH"; - - /// \brief Interface to a log file - class GZ_TRANSPORT_LOG_VISIBLE Log - { - /// \brief constructor - public: Log(); - - /// \brief move constructor - /// \param[in] _old the instance being moved into this one - public: Log(Log &&_old); // NOLINT - - /// \brief destructor - public: ~Log(); - - /// \brief Indicate if a log has been successfully opened - /// \return true if a log is open - public: bool Valid() const; - - /// \brief Get the schema version of the opened log - /// \return the current version of the schema in the log file - /// \return empty string if the log has not been opened - public: std::string Version() const; - - /// \brief Open a log file - /// \param[in] _file path to log file - /// \param[in] _mode flag indicating read only or read/write - /// Can use (in or out) - /// \return True if the log file was successfully opened, false - /// otherwise. - public: bool Open(const std::string &_file, - std::ios_base::openmode _mode = std::ios_base::in); - - /// \brief Get the name of the log file. - /// \return The name of the log file, or an empty string if Open has - /// not been successfully called. - public: std::string Filename() const; - - /// \brief Get a Descriptor for this log. The Descriptor will be - /// generated the first time that this function is called after a new - /// file has been opened. - /// \return A Descriptor for this log, if a log file is currently - /// loaded. If no log file is loaded, this returns a nullptr. - public: const log::Descriptor *Descriptor() const; - - /// \brief Insert a message into the log file - /// \param[in] _time Time the message was received (ns since Unix epoch) - /// \param[in] _topic Name of the topic the message was on - /// \param[in] _type Name of the message type - /// \param[in] _data pointer to a buffer containing the message data - /// \param[in] _len number of bytes of data - /// \return true if the message was successfully inserted - public: bool InsertMessage( - const std::chrono::nanoseconds &_time, - const std::string &_topic, const std::string &_type, - const void *_data, std::size_t _len); - - /// \brief Get messages according to the specified options. By default, - /// it will query all messages over the entire time range of the log. - /// \param[in] _options A QueryOptions type to indicate what kind of - /// messages you would like to query. - /// \return A Batch which matches the requested QueryOptions. - public: Batch QueryMessages( - const QueryOptions &_options = AllTopics()); - - /// \brief Get start time of the log, or in other words the - /// time of the first message found in the log - /// \return start time of the log, or zero if the log is not - /// valid or if data retrieval failed. - public: std::chrono::nanoseconds StartTime() const; - - /// \brief Get end time of the log, or in other words the - /// time of the last message found in the log - /// \return end time of the log, or zero if the log is not - /// valid or if data retrieval failed. - public: std::chrono::nanoseconds EndTime() const; - - /// \internal Implementation for this class - private: class Implementation; + /// \brief constructor + public: Log(); + + /// \brief move constructor + /// \param[in] _old the instance being moved into this one + public: Log(Log &&_old); // NOLINT + + /// \brief destructor + public: ~Log(); + + /// \brief Indicate if a log has been successfully opened + /// \return true if a log is open + public: bool Valid() const; + + /// \brief Get the schema version of the opened log + /// \return the current version of the schema in the log file + /// \return empty string if the log has not been opened + public: std::string Version() const; + + /// \brief Open a log file + /// \param[in] _file path to log file + /// \param[in] _mode flag indicating read only or read/write + /// Can use (in or out) + /// \return True if the log file was successfully opened, false + /// otherwise. + public: bool Open(const std::string &_file, + std::ios_base::openmode _mode = std::ios_base::in); + + /// \brief Get the name of the log file. + /// \return The name of the log file, or an empty string if Open has + /// not been successfully called. + public: std::string Filename() const; + + /// \brief Get a Descriptor for this log. The Descriptor will be + /// generated the first time that this function is called after a new + /// file has been opened. + /// \return A Descriptor for this log, if a log file is currently + /// loaded. If no log file is loaded, this returns a nullptr. + public: const log::Descriptor *Descriptor() const; + + /// \brief Insert a message into the log file + /// \param[in] _time Time the message was received (ns since Unix epoch) + /// \param[in] _topic Name of the topic the message was on + /// \param[in] _type Name of the message type + /// \param[in] _data pointer to a buffer containing the message data + /// \param[in] _len number of bytes of data + /// \return true if the message was successfully inserted + public: bool InsertMessage( + const std::chrono::nanoseconds &_time, + const std::string &_topic, const std::string &_type, + const void *_data, std::size_t _len); + + /// \brief Get messages according to the specified options. By default, + /// it will query all messages over the entire time range of the log. + /// \param[in] _options A QueryOptions type to indicate what kind of + /// messages you would like to query. + /// \return A Batch which matches the requested QueryOptions. + public: Batch QueryMessages( + const QueryOptions &_options = AllTopics()); + + /// \brief Get start time of the log, or in other words the + /// time of the first message found in the log + /// \return start time of the log, or zero if the log is not + /// valid or if data retrieval failed. + public: std::chrono::nanoseconds StartTime() const; + + /// \brief Get end time of the log, or in other words the + /// time of the last message found in the log + /// \return end time of the log, or zero if the log is not + /// valid or if data retrieval failed. + public: std::chrono::nanoseconds EndTime() const; + + /// \internal Implementation for this class + private: class Implementation; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -125,14 +121,12 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Private implementation - private: std::unique_ptr dataPtr; + /// \brief Private implementation + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } - } -} -#endif + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::log +#endif // GZ_TRANSPORT_LOG_LOG_HH_ diff --git a/log/include/gz/transport/log/Message.hh b/log/include/gz/transport/log/Message.hh index 273e3e5e1..12bd86530 100644 --- a/log/include/gz/transport/log/Message.hh +++ b/log/include/gz/transport/log/Message.hh @@ -24,69 +24,65 @@ #include #include -namespace gz +namespace gz::transport::log { - namespace transport - { - namespace log - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \brief Forward Declarations - class MessagePrivate; + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \brief Forward Declarations + class MessagePrivate; - /// \brief Represents a message in a bag file. - class GZ_TRANSPORT_LOG_VISIBLE Message - { - /// \brief Default constructor - public: Message(); + /// \brief Represents a message in a bag file. + class GZ_TRANSPORT_LOG_VISIBLE Message + { + /// \brief Default constructor + public: Message(); - /// \brief Construct with data. - /// \internal - /// Referrences and pointers are borrowed, and must be kept alive by - /// the creator for as long as an instance lives. - /// This constructor is public for the sake of unit testing, but is not - /// expected to be called by a user. - /// \param[in] _timeRecv time the message was received - /// \param[in] _data the serialized message - /// \param[in] _dataLen number of bytes in _data - /// \param[in] _type the name of the message type - /// \param[in] _typeLen the length of _type - /// \param[in] _topic the name of the topic the message was published to - /// \param[in] _topicLen the length of _topic - public: Message( - const std::chrono::nanoseconds &_timeRecv, - const void *_data, std::size_t _dataLen, - const char *_type, std::size_t _typeLen, - const char *_topic, std::size_t _topicLen); + /// \brief Construct with data. + /// \internal + /// Referrences and pointers are borrowed, and must be kept alive by + /// the creator for as long as an instance lives. + /// This constructor is public for the sake of unit testing, but is not + /// expected to be called by a user. + /// \param[in] _timeRecv time the message was received + /// \param[in] _data the serialized message + /// \param[in] _dataLen number of bytes in _data + /// \param[in] _type the name of the message type + /// \param[in] _typeLen the length of _type + /// \param[in] _topic the name of the topic the message was published to + /// \param[in] _topicLen the length of _topic + public: Message( + const std::chrono::nanoseconds &_timeRecv, + const void *_data, std::size_t _dataLen, + const char *_type, std::size_t _typeLen, + const char *_topic, std::size_t _topicLen); - /// \brief No move constructor to prevent borrowed pointers from - /// living beyond creator's expectations. - public: Message(Message && _other) = delete; + /// \brief No move constructor to prevent borrowed pointers from + /// living beyond creator's expectations. + public: Message(Message && _other) = delete; - /// \brief No copy constructor to prevent borrowed pointers from - /// living beyond creator's expectations. - public: Message(const Message & _other) = delete; + /// \brief No copy constructor to prevent borrowed pointers from + /// living beyond creator's expectations. + public: Message(const Message & _other) = delete; - /// \brief Destructor - public: ~Message(); + /// \brief Destructor + public: ~Message(); - /// \brief Get the message data - /// \return The raw data for this message - public: std::string Data() const; + /// \brief Get the message data + /// \return The raw data for this message + public: std::string Data() const; - /// \brief Get the message type as a string - /// \return The message type name - public: std::string Type() const; + /// \brief Get the message type as a string + /// \return The message type name + public: std::string Type() const; - /// \brief Get the Topic name as a string - /// \return The topic for the message - public: std::string Topic() const; + /// \brief Get the Topic name as a string + /// \return The topic for the message + public: std::string Topic() const; - /// \brief Return the time the message was received - /// \return The time the message was received - public: const std::chrono::nanoseconds &TimeReceived() const; + /// \brief Return the time the message was received + /// \return The time the message was received + public: const std::chrono::nanoseconds &TimeReceived() const; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -94,14 +90,12 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Private Implementation Pointer - private: std::unique_ptr dataPtr; + /// \brief Private Implementation Pointer + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } - } -} -#endif + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::log +#endif // GZ_TRANSPORT_LOG_MESSAGE_HH_ diff --git a/log/include/gz/transport/log/MsgIter.hh b/log/include/gz/transport/log/MsgIter.hh index 356973330..84337289b 100644 --- a/log/include/gz/transport/log/MsgIter.hh +++ b/log/include/gz/transport/log/MsgIter.hh @@ -24,87 +24,81 @@ #include #include -namespace gz +namespace gz::transport::log { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \brief Forward Declarations + class MsgIterPrivate; + class Log; + + /// \brief Implements iterator for reading messages + class GZ_TRANSPORT_LOG_VISIBLE MsgIter { - namespace log - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \brief Forward Declarations - class MsgIterPrivate; - class Log; - - /// \brief Implements iterator for reading messages - class GZ_TRANSPORT_LOG_VISIBLE MsgIter - { - /// \brief Default constructor - public: MsgIter(); - - /// \brief Move Constructor - /// \param[in] _orig the instance being copied - public: MsgIter(MsgIter &&_orig); // NOLINT - - /// \brief Destructor; - public: ~MsgIter(); - - /// \brief Copy-assignment operator - /// \param[in] _orig the instance being copied - /// \return a reference to this instance - // public: MsgIter &operator=(const MsgIter &_orig); - - /// \brief Prefix increment - /// \return a reference to this instance - public: MsgIter &operator++(); - - /// \brief Equality operator - /// \param[in] _other the iterator this is being compared to - /// \return true if the two iterator point to the same message - public: bool operator==(const MsgIter &_other) const; - - /// \brief Inequality operator - /// \param[in] _other the iterator this is being compared to - /// \return false if the two iterator point to the same message - public: bool operator!=(const MsgIter &_other) const; - - /// \brief Move assignement operator - /// \param[in] _other the new iterator replacing the current one - /// \return The updated MsgIter. - public: MsgIter& operator=(MsgIter &&_other); // NOLINT - - /// \brief Dereference Operator - /// \return a reference to the message this is pointing to - public: const Message &operator*() const; - - /// \brief arrow dereference operator - /// \return a pointer to the message this is pointing to - public: const Message *operator->() const; + /// \brief Default constructor + public: MsgIter(); + + /// \brief Move Constructor + /// \param[in] _orig the instance being copied + public: MsgIter(MsgIter &&_orig); // NOLINT + + /// \brief Destructor; + public: ~MsgIter(); + + /// \brief Copy-assignment operator + /// \param[in] _orig the instance being copied + /// \return a reference to this instance + // public: MsgIter &operator=(const MsgIter &_orig); + + /// \brief Prefix increment + /// \return a reference to this instance + public: MsgIter &operator++(); + + /// \brief Equality operator + /// \param[in] _other the iterator this is being compared to + /// \return true if the two iterator point to the same message + public: bool operator==(const MsgIter &_other) const; + + /// \brief Inequality operator + /// \param[in] _other the iterator this is being compared to + /// \return false if the two iterator point to the same message + public: bool operator!=(const MsgIter &_other) const; + + /// \brief Move assignement operator + /// \param[in] _other the new iterator replacing the current one + /// \return The updated MsgIter. + public: MsgIter& operator=(MsgIter &&_other); // NOLINT + + /// \brief Dereference Operator + /// \return a reference to the message this is pointing to + public: const Message &operator*() const; + + /// \brief arrow dereference operator + /// \return a pointer to the message this is pointing to + public: const Message *operator->() const; #ifdef _WIN32 -// Disable warning C4251 which is triggered by -// std::* + // Disable warning C4251 which is triggered by + // std::* #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Private Implementation Pointer - private: std::unique_ptr dataPtr; + /// \brief Private Implementation Pointer + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - /// \brief Construct with private implementation - /// \param[in] _pimpl a private implementation pointer - /// \internal - private: MsgIter( - std::unique_ptr &&_pimpl); // NOLINT(build/c++11) - - /// \brief can use private constructor - friend class Batch; - }; - } - } - } -} -#endif + /// \brief Construct with private implementation + /// \param[in] _pimpl a private implementation pointer + /// \internal + private: MsgIter( + std::unique_ptr &&_pimpl); // NOLINT(build/c++11) + + /// \brief can use private constructor + friend class Batch; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::log +#endif // GZ_TRANSPORT_LOG_MSGITER_HH_ diff --git a/log/include/gz/transport/log/Playback.hh b/log/include/gz/transport/log/Playback.hh index dfd5ba531..5144f0a27 100644 --- a/log/include/gz/transport/log/Playback.hh +++ b/log/include/gz/transport/log/Playback.hh @@ -26,118 +26,114 @@ #include #include -namespace gz +namespace gz::transport::log { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + // Forward declarations + class PlaybackHandle; + using PlaybackHandlePtr = std::shared_ptr; + + ////////////////////////////////////////////////// + /// \brief Initiates playback of Gazebo Transport topics + /// This class makes it easy to play topics from a log file + /// + /// Responsibilities: topic name matching and initiating the playback + class GZ_TRANSPORT_LOG_VISIBLE Playback { - namespace log - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - // Forward declarations - class PlaybackHandle; - using PlaybackHandlePtr = std::shared_ptr; - - ////////////////////////////////////////////////// - /// \brief Initiates playback of Gazebo Transport topics - /// This class makes it easy to play topics from a log file - /// - /// Responsibilities: topic name matching and initiating the playback - class GZ_TRANSPORT_LOG_VISIBLE Playback - { - /// \brief Constructor - /// \param[in] _file path to log file - /// \param[in] _nodeOptions Options for creating a node. - public: explicit Playback(const std::string &_file, - const NodeOptions &_nodeOptions = NodeOptions()); - - /// \brief move constructor - /// \param[in] _old the instance being moved into this one - public: Playback(Playback &&_old); // NOLINT - - /// \brief destructor - public: ~Playback(); - - /// \brief Begin playing messages - /// \param[in] _waitAfterAdvertising How long to wait before the - /// publications begin after advertising the topics that will be played - /// back. - /// \param[in] _msgWaiting True to wait between publication of - /// messages based on the message timestamps. False to playback - /// messages as fast as possible. Default value is true. - /// - /// \note The topic discovery process will need some time before - /// publishing begins, or else subscribers in other processes will miss - /// the outgoing messages. The default value is recommended unless you - /// are confident in the timing of your system. - /// - /// \remark If your application uses another library that uses sqlite3, - /// it may be unsafe to start multiple simultaneous PlaybackHandles from - /// the same Playback instance, because they will interact with the same - /// sqlite3 database in multiple threads (see https://www.sqlite.org/threadsafe.html). - /// In most cases there should be no issue, but if you or a library you - /// are using calls sqlite3_config(~) to change the threading mode to - /// Single-thread or Multi-thread (instead of the default setting of - /// Seralized), then starting multiple simultaneous playbacks from the - /// same log file could be dangerous. - /// - /// \return A handle for managing the playback of the log. You must hold - /// onto this object in order for the playback to continue, or else it - /// will be cut short. - /// - /// If an error prevents the playback from starting, this will return a - /// nullptr. - public: [[nodiscard]] PlaybackHandlePtr Start( - const std::chrono::nanoseconds &_waitAfterAdvertising = - std::chrono::seconds(1), - bool _msgWaiting = true) const; - - /// \brief Check if this Playback object has a valid log to play back - /// \return true if this has a valid log to play back, otherwise false. - public: bool Valid() const; - - /// \brief Add a topic to be played back (exact match only) - /// \param[in] _topic The exact topic name - /// \note This method attempts to advertise the topic immediately. - /// The publisher will be kept until this is destructed. - /// \return True if the topic exists in the log, false if it does not - /// exist or if the log is not valid. - public: bool AddTopic(const std::string &_topic); - - /// \brief Add a topic to be played back (regex match) - /// \param[in] _topic Pattern to match against topic names - /// \note This method attempts to advertise topics immediately. - /// These publishers will be kept until this is destructed. - /// \return number of topics that will be published or -1 if this - /// Playback object is not valid. - public: int64_t AddTopic(const std::regex &_topic); - - /// \brief Remove a topic from being played back. - /// - /// \note If neither AddTopic() nor RemoveTopic() were called prior to - /// this function, we will assume you want all of the topics and then - /// remove the one passed in here. - /// - /// \param[in] _topic The exact topic name to remove - /// \return True if the topic was in the list and has been removed, - /// false otherwise. - public: bool RemoveTopic(const std::string &_topic); - - /// \brief Remove all topics matching the specified pattern from being - /// played back. - /// - /// \note If neither AddTopic() nor RemoveTopic() were called prior to - /// this function, we will assume you want all of the topics and then - /// remove the one passed in here. - /// - /// \param[in] _topic The pattern of topics to be removed - /// \return The number of topics that have been removed from playback - /// due to this function call. - public: int64_t RemoveTopic(const std::regex &_topic); - - /// \internal Implementation of this class - private: class Implementation; + /// \brief Constructor + /// \param[in] _file path to log file + /// \param[in] _nodeOptions Options for creating a node. + public: explicit Playback(const std::string &_file, + const NodeOptions &_nodeOptions = NodeOptions()); + + /// \brief move constructor + /// \param[in] _old the instance being moved into this one + public: Playback(Playback &&_old); // NOLINT + + /// \brief destructor + public: ~Playback(); + + /// \brief Begin playing messages + /// \param[in] _waitAfterAdvertising How long to wait before the + /// publications begin after advertising the topics that will be played + /// back. + /// \param[in] _msgWaiting True to wait between publication of + /// messages based on the message timestamps. False to playback + /// messages as fast as possible. Default value is true. + /// + /// \note The topic discovery process will need some time before + /// publishing begins, or else subscribers in other processes will miss + /// the outgoing messages. The default value is recommended unless you + /// are confident in the timing of your system. + /// + /// \remark If your application uses another library that uses sqlite3, + /// it may be unsafe to start multiple simultaneous PlaybackHandles from + /// the same Playback instance, because they will interact with the same + /// sqlite3 database in multiple threads (see https://www.sqlite.org/threadsafe.html). + /// In most cases there should be no issue, but if you or a library you + /// are using calls sqlite3_config(~) to change the threading mode to + /// Single-thread or Multi-thread (instead of the default setting of + /// Seralized), then starting multiple simultaneous playbacks from the + /// same log file could be dangerous. + /// + /// \return A handle for managing the playback of the log. You must hold + /// onto this object in order for the playback to continue, or else it + /// will be cut short. + /// + /// If an error prevents the playback from starting, this will return a + /// nullptr. + public: [[nodiscard]] PlaybackHandlePtr Start( + const std::chrono::nanoseconds &_waitAfterAdvertising = + std::chrono::seconds(1), + bool _msgWaiting = true) const; + + /// \brief Check if this Playback object has a valid log to play back + /// \return true if this has a valid log to play back, otherwise false. + public: bool Valid() const; + + /// \brief Add a topic to be played back (exact match only) + /// \param[in] _topic The exact topic name + /// \note This method attempts to advertise the topic immediately. + /// The publisher will be kept until this is destructed. + /// \return True if the topic exists in the log, false if it does not + /// exist or if the log is not valid. + public: bool AddTopic(const std::string &_topic); + + /// \brief Add a topic to be played back (regex match) + /// \param[in] _topic Pattern to match against topic names + /// \note This method attempts to advertise topics immediately. + /// These publishers will be kept until this is destructed. + /// \return number of topics that will be published or -1 if this + /// Playback object is not valid. + public: int64_t AddTopic(const std::regex &_topic); + + /// \brief Remove a topic from being played back. + /// + /// \note If neither AddTopic() nor RemoveTopic() were called prior to + /// this function, we will assume you want all of the topics and then + /// remove the one passed in here. + /// + /// \param[in] _topic The exact topic name to remove + /// \return True if the topic was in the list and has been removed, + /// false otherwise. + public: bool RemoveTopic(const std::string &_topic); + + /// \brief Remove all topics matching the specified pattern from being + /// played back. + /// + /// \note If neither AddTopic() nor RemoveTopic() were called prior to + /// this function, we will assume you want all of the topics and then + /// remove the one passed in here. + /// + /// \param[in] _topic The pattern of topics to be removed + /// \return The number of topics that have been removed from playback + /// due to this function call. + public: int64_t RemoveTopic(const std::regex &_topic); + + /// \internal Implementation of this class + private: class Implementation; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -145,75 +141,75 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Private implementation - private: std::unique_ptr dataPtr; + /// \brief Private implementation + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - - ////////////////////////////////////////////////// - /// \brief Handles the playback of Gazebo Transport topics. - /// This class allows you to manage a log playback once it has started. - /// You must hang onto the PlaybackHandle or else the playback will end - /// early. - /// - /// Responsibilities: time keeping, multiple thread safety, publishing - /// data to topics, and stopping playback. - class GZ_TRANSPORT_LOG_VISIBLE PlaybackHandle - { - /// \brief Stop playing messages - public: void Stop(); + }; + + ////////////////////////////////////////////////// + /// \brief Handles the playback of Gazebo Transport topics. + /// This class allows you to manage a log playback once it has started. + /// You must hang onto the PlaybackHandle or else the playback will end + /// early. + /// + /// Responsibilities: time keeping, multiple thread safety, publishing + /// data to topics, and stopping playback. + class GZ_TRANSPORT_LOG_VISIBLE PlaybackHandle + { + /// \brief Stop playing messages + public: void Stop(); - /// \brief Jump current playback time to a specific elapsed time - /// \param[in] _newElapsedTime Elapsed time at which playback will jump - public: void Seek(const std::chrono::nanoseconds &_newElapsedTime); + /// \brief Jump current playback time to a specific elapsed time + /// \param[in] _newElapsedTime Elapsed time at which playback will jump + public: void Seek(const std::chrono::nanoseconds &_newElapsedTime); - /// \brief Step the playback by a given amount of nanoseconds - /// \pre Playback must be previously paused - /// \param[in] _stepDuration Length of the step in nanoseconds - public: void Step(const std::chrono::nanoseconds &_stepDuration); + /// \brief Step the playback by a given amount of nanoseconds + /// \pre Playback must be previously paused + /// \param[in] _stepDuration Length of the step in nanoseconds + public: void Step(const std::chrono::nanoseconds &_stepDuration); - /// \brief Pauses the playback - public: void Pause(); + /// \brief Pauses the playback + public: void Pause(); - /// \brief Unpauses the playback - public: void Resume(); + /// \brief Unpauses the playback + public: void Resume(); - /// \brief Check pause status - public: bool IsPaused() const; + /// \brief Check pause status + public: bool IsPaused() const; - /// \brief Block until playback runs out of messages to publish - public: void WaitUntilFinished(); + /// \brief Block until playback runs out of messages to publish + public: void WaitUntilFinished(); - /// \brief Check if this playback is finished - /// \return true if all messages have finished playing; false otherwise. - public: bool Finished() const; + /// \brief Check if this playback is finished + /// \return true if all messages have finished playing; false otherwise. + public: bool Finished() const; - /// \brief Gets start time of the log being played - /// \return start time of the log, in nanoseconds - public: std::chrono::nanoseconds StartTime() const; + /// \brief Gets start time of the log being played + /// \return start time of the log, in nanoseconds + public: std::chrono::nanoseconds StartTime() const; - /// \brief Gets current time of the log being played - /// \return current time of the log playback, in nanoseconds - public: std::chrono::nanoseconds CurrentTime() const; + /// \brief Gets current time of the log being played + /// \return current time of the log playback, in nanoseconds + public: std::chrono::nanoseconds CurrentTime() const; - /// \brief Gets end time of the log being played - /// \return end time of the log, in nanoseconds - public: std::chrono::nanoseconds EndTime() const; + /// \brief Gets end time of the log being played + /// \return end time of the log, in nanoseconds + public: std::chrono::nanoseconds EndTime() const; - /// \brief Destructor - public: ~PlaybackHandle(); + /// \brief Destructor + public: ~PlaybackHandle(); - // Friendship - friend class Playback; + // Friendship + friend class Playback; - // Forward declaration of implementation class - private: class Implementation; + // Forward declaration of implementation class + private: class Implementation; - /// \brief Private constructor. This can only be called by Playback. - private: PlaybackHandle( - std::unique_ptr &&_internal); // NOLINT + /// \brief Private constructor. This can only be called by Playback. + private: PlaybackHandle( + std::unique_ptr &&_internal); // NOLINT #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -221,14 +217,12 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal Pointer to implementation class - private: std::unique_ptr dataPtr; + /// \internal Pointer to implementation class + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } - } -} -#endif + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::log +#endif // GZ_TRANSPORT_LOG_PLAYBACK_HH_ diff --git a/log/include/gz/transport/log/QualifiedTime.hh b/log/include/gz/transport/log/QualifiedTime.hh index 74cb7a36d..709c68937 100644 --- a/log/include/gz/transport/log/QualifiedTime.hh +++ b/log/include/gz/transport/log/QualifiedTime.hh @@ -24,152 +24,148 @@ #include #include -namespace gz +namespace gz::transport::log { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + ////////////////////////////////////////////////// + /// \brief Since time is continuous, it may be difficult to know the exact + /// time stamp of a desired message. The QualifiedTime class provides a + /// way to tailor how a time stamp is interpreted by the message query. + /// + /// Note that the value of this time object may be interpreted as a + /// relative time or as an absolute time stamp depending on the context in + /// which it gets used. + class GZ_TRANSPORT_LOG_VISIBLE QualifiedTime { - namespace log + /// \brief The Qualifier determines the behavior of how a message is + /// selected. + public: enum class Qualifier : int64_t { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - ////////////////////////////////////////////////// - /// \brief Since time is continuous, it may be difficult to know the exact - /// time stamp of a desired message. The QualifiedTime class provides a - /// way to tailor how a time stamp is interpreted by the message query. - /// - /// Note that the value of this time object may be interpreted as a - /// relative time or as an absolute time stamp depending on the context in - /// which it gets used. - class GZ_TRANSPORT_LOG_VISIBLE QualifiedTime - { - /// \brief The Qualifier determines the behavior of how a message is - /// selected. - public: enum class Qualifier : int64_t - { - /// \brief This point in time should be seen as a closed (inclusive) - /// time marker. When used in a QualifiedTimeRange, the range will - /// include this exact point in time. - INCLUSIVE = 0, - - /// \brief This point in time should be seen as an open (exclusive) - /// time marker. When used in a QualifiedTimeRange, the range will - /// NOT include this exact point in time, but it will include - /// everything leading up to it. - EXCLUSIVE - }; - - /// \brief Convenient typedef for our time representation. Note that any - /// std::chrono::duration type can be implicitly converted to this type. - /// E.g. you can pass a - /// - /// \code - /// std::chrono::seconds(value) - /// std::chrono::milliseconds(value) - /// std::chrono::minutes(value) - /// // ... ect ... - /// \endcode - /// - /// into any function that accepts this Time type. - using Time = std::chrono::nanoseconds; - - /// \brief Construct a qualified time specifier. - /// \param[in] _time The time stamp that is used as the focal point of - /// this qualified time. - /// \param[in] _qualifier The qualifier that determines the exact - /// interpretation of the _time value. - public: QualifiedTime(const Time &_time, - Qualifier _qualifier = Qualifier::INCLUSIVE); - - /// \brief Construct a qualified time specifier. This allows implicit - /// conversion from any std::chrono::duration type. - /// \param[in] _time The time stamp that is used as the focal point of - /// this qualified time. - /// \param[in] _qualifier The qualifier that determines the exact - /// interpretation of the _time value. - public: template - QualifiedTime(const std::chrono::duration &_time, - Qualifier _qualifier = Qualifier::INCLUSIVE) - : QualifiedTime(static_cast(_time), _qualifier) { } - - /// \brief Default constructor. The time will be treated as - /// indeterminate. This means that the QualifiedTime object will be - /// taken to indicate that no time has been specified at all. - /// \sa IsIndeterminate() - public: QualifiedTime(/* Indeterminate */); - - /// \brief Copy constructor. - /// \param[in] _other Another QualifiedTime - public: QualifiedTime(const QualifiedTime &_other); - - /// \brief Copy assignment operator. - /// \param[in] _other Another QualifiedTime - /// \return Reference to this object - public: QualifiedTime &operator=(const QualifiedTime &_other); - - /// \brief move constructor - /// \param[in] _old the instance being moved into this one - public: QualifiedTime(QualifiedTime &&_old) = default; // NOLINT - - /// \brief move assignment operator - /// \return Reference to this object - public: QualifiedTime &operator=( - QualifiedTime &&) = default; // NOLINT(build/c++11) - - /// \brief Equality operator. - /// \param[in] _other Another QualifiedTime - /// \return True if the times are equal. When either time is - /// indeterminate, this will always return false, similar to the - /// behavior of NaN comparisons. - public: bool operator==(const QualifiedTime &_other) const; - - /// \brief Inequality operator. - /// \param[in] _other Another QualifiedTime - /// \return Opposite value of operator==(const QualifiedTime &) - public: bool operator!=(const QualifiedTime &_other) const; - - /// \brief Indicates whether this QualifiedTime object is indeterminate. - /// - /// When an indeterminate time is used as the end of a range, it implies - /// that the range should go on endlessly. When used as the beginning of - /// a range, it means that the range should extend as far into the past - /// as possible. - /// - /// \return true if this QualifiedTime is indeterminate, or false if it - /// does have a determined time. - public: bool IsIndeterminate() const; - - /// \brief Get the time stamp for this qualified time, unless the time - /// is indeterminate. - /// \return A pointer to the time value that is specified by this - /// QualifiedTime object, or a nullptr if this QualifiedTime is - /// indeterminate. - public: const Time *GetTime() const; - - /// \brief Get the qualifier for this qualified time, unless the time - /// is indeterminate. - /// \return A pointer to the qualifier that is specified by this - /// QualifiedTime object, or a nullptr if this QualifiedTime is - /// indeterminate. - public: const Qualifier *GetQualifier() const; - - /// \brief Set the time that this QualifiedTime object represents. - /// \param[in] _time The time stamp that is used as the focal point of - /// this qualified time. - /// \param[in] _qualifier The qualifier that determines the exact - /// interpretation of the _time value. - public: void SetTime(const Time &_time, - Qualifier _qualifier = Qualifier::INCLUSIVE); - - /// \brief Set this QualifiedTime object to be indeterminate. - /// \sa IsIndeterminate() - public: void Clear(); - - /// \brief Destructor - public: ~QualifiedTime(); - - /// \internal Implementation class - private: class Implementation; + /// \brief This point in time should be seen as a closed (inclusive) + /// time marker. When used in a QualifiedTimeRange, the range will + /// include this exact point in time. + INCLUSIVE = 0, + + /// \brief This point in time should be seen as an open (exclusive) + /// time marker. When used in a QualifiedTimeRange, the range will + /// NOT include this exact point in time, but it will include + /// everything leading up to it. + EXCLUSIVE + }; + + /// \brief Convenient typedef for our time representation. Note that any + /// std::chrono::duration type can be implicitly converted to this type. + /// E.g. you can pass a + /// + /// \code + /// std::chrono::seconds(value) + /// std::chrono::milliseconds(value) + /// std::chrono::minutes(value) + /// // ... ect ... + /// \endcode + /// + /// into any function that accepts this Time type. + using Time = std::chrono::nanoseconds; + + /// \brief Construct a qualified time specifier. + /// \param[in] _time The time stamp that is used as the focal point of + /// this qualified time. + /// \param[in] _qualifier The qualifier that determines the exact + /// interpretation of the _time value. + public: QualifiedTime(const Time &_time, + Qualifier _qualifier = Qualifier::INCLUSIVE); + + /// \brief Construct a qualified time specifier. This allows implicit + /// conversion from any std::chrono::duration type. + /// \param[in] _time The time stamp that is used as the focal point of + /// this qualified time. + /// \param[in] _qualifier The qualifier that determines the exact + /// interpretation of the _time value. + public: template + QualifiedTime(const std::chrono::duration &_time, + Qualifier _qualifier = Qualifier::INCLUSIVE) + : QualifiedTime(static_cast(_time), _qualifier) { } + + /// \brief Default constructor. The time will be treated as + /// indeterminate. This means that the QualifiedTime object will be + /// taken to indicate that no time has been specified at all. + /// \sa IsIndeterminate() + public: QualifiedTime(/* Indeterminate */); + + /// \brief Copy constructor. + /// \param[in] _other Another QualifiedTime + public: QualifiedTime(const QualifiedTime &_other); + + /// \brief Copy assignment operator. + /// \param[in] _other Another QualifiedTime + /// \return Reference to this object + public: QualifiedTime &operator=(const QualifiedTime &_other); + + /// \brief move constructor + /// \param[in] _old the instance being moved into this one + public: QualifiedTime(QualifiedTime &&_old) = default; // NOLINT + + /// \brief move assignment operator + /// \return Reference to this object + public: QualifiedTime &operator=( + QualifiedTime &&) = default; // NOLINT(build/c++11) + + /// \brief Equality operator. + /// \param[in] _other Another QualifiedTime + /// \return True if the times are equal. When either time is + /// indeterminate, this will always return false, similar to the + /// behavior of NaN comparisons. + public: bool operator==(const QualifiedTime &_other) const; + + /// \brief Inequality operator. + /// \param[in] _other Another QualifiedTime + /// \return Opposite value of operator==(const QualifiedTime &) + public: bool operator!=(const QualifiedTime &_other) const; + + /// \brief Indicates whether this QualifiedTime object is indeterminate. + /// + /// When an indeterminate time is used as the end of a range, it implies + /// that the range should go on endlessly. When used as the beginning of + /// a range, it means that the range should extend as far into the past + /// as possible. + /// + /// \return true if this QualifiedTime is indeterminate, or false if it + /// does have a determined time. + public: bool IsIndeterminate() const; + + /// \brief Get the time stamp for this qualified time, unless the time + /// is indeterminate. + /// \return A pointer to the time value that is specified by this + /// QualifiedTime object, or a nullptr if this QualifiedTime is + /// indeterminate. + public: const Time *GetTime() const; + + /// \brief Get the qualifier for this qualified time, unless the time + /// is indeterminate. + /// \return A pointer to the qualifier that is specified by this + /// QualifiedTime object, or a nullptr if this QualifiedTime is + /// indeterminate. + public: const Qualifier *GetQualifier() const; + + /// \brief Set the time that this QualifiedTime object represents. + /// \param[in] _time The time stamp that is used as the focal point of + /// this qualified time. + /// \param[in] _qualifier The qualifier that determines the exact + /// interpretation of the _time value. + public: void SetTime(const Time &_time, + Qualifier _qualifier = Qualifier::INCLUSIVE); + + /// \brief Set this QualifiedTime object to be indeterminate. + /// \sa IsIndeterminate() + public: void Clear(); + + /// \brief Destructor + public: ~QualifiedTime(); + + /// \internal Implementation class + private: class Implementation; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -177,128 +173,128 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal PIMPL pointer - /// We need a custom deleter here due to a compiler bug in MSVC 2017 - private: std::unique_ptr dataPtr; + /// \internal PIMPL pointer + /// We need a custom deleter here due to a compiler bug in MSVC 2017 + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - - ////////////////////////////////////////////////// - /// \brief The QualifiedTimeRange class provides a pair of qualified times - /// that represent a range. This is used to specify a desired time range - /// to the BasicQueryOptions class. - class GZ_TRANSPORT_LOG_VISIBLE QualifiedTimeRange - { - /// \brief Construct a time range. - /// \param[in] _begin The beginning of the time range. - /// \param[in] _end The end of the time range. - /// \sa From() - /// \sa Until() - /// \sa AllTime() - public: QualifiedTimeRange( - const QualifiedTime &_begin, - const QualifiedTime &_end); - - /// \brief Copy constructor - /// \param[in] _other Another QualifiedTimeRange - public: QualifiedTimeRange(const QualifiedTimeRange &_other); - - /// \brief Copy assignment operator - /// \param[in] _other Another QualifiedTimeRange - /// \return Reference to this object - public: QualifiedTimeRange &operator=(const QualifiedTimeRange &_other); - - /// \brief Default move constructor - /// \param[in] _old the instance being moved into this one - public: QualifiedTimeRange(QualifiedTimeRange &&_old); // NOLINT - - /// \brief Default move assignment - /// \return Reference to this object - public: QualifiedTimeRange &operator=( - QualifiedTimeRange &&) = default; // NOLINT(build/c++11) - - /// \brief Equality operator. - /// \param[in] _other Another QualifiedTimeRange - /// \return true if the time ranges represented by each object are - /// equivalent - public: bool operator==(const QualifiedTimeRange &_other) const; - - /// \brief Inequality operator. - /// \param[in] _other Another QualifiedTimeRange - /// \return Opposite of operator==(const QualifiedTimeRange &) - public: bool operator!=(const QualifiedTimeRange &_other) const; - - /// \brief Construct a time range that begins at _begin and never ends. - /// \param[in] _begin The beginning of the time range. - /// \return A time range that begins at _begin and never ends. - public: static QualifiedTimeRange From(const QualifiedTime &_begin); - - /// \brief Construct a time range that ends at _end and has no - /// beginning. - /// \param[in] _end The end of the time range. - /// \return A time range that ends at _end and has no beginning. - public: static QualifiedTimeRange Until(const QualifiedTime &_end); - - /// \brief Construct a time range that has no beginning or end. - /// \return A time range that has no beginning or end. - public: static QualifiedTimeRange AllTime(); - - /// \brief Get a reference to the start time of this range. - /// \return A reference to the start time. - public: const QualifiedTime &Beginning() const; - - /// \brief Get a reference to the end time of this range. - /// \return A reference to the end time. - public: const QualifiedTime &Ending() const; - - /// \brief Set the start time of this range. Passing in an indeterminate - /// QualifiedTime (its default constructor) will tell this range to have - /// no beginning (effectively, it should start at the beginning of the - /// log). - /// \param[in] _begin The start time of this range. - /// \return True if the new range is valid. False if the range is now - /// invalid. The _begin value will be accepted either way. - /// \sa SetRange() - /// \sa Valid() - public: bool SetBeginning(const QualifiedTime &_begin); - - /// \brief Set the finish time of this range. Passing in an - /// indeterminate QualifiedTime (its default constructor) will tell this - /// range to have no end (effectively, it should not stop until the end - /// of the log). - /// \param[in] _end The finish time of this range. - /// \return True if this new range is valid. False if the range is now - /// invalid. The _end value will be accepted either way. - /// \sa SetRange() - /// \sa Valid() - public: bool SetEnding(const QualifiedTime &_end); - - /// \brief Set both endpoints of the range. - /// \param[in] _begin The start time of this range. - /// \param[in] _end The end time of this range. - /// \return True if this new range is valid. False if the range is now - /// invalid. The values for _begin and _end will be accepted either - /// way. - /// \sa SetBeginning() - /// \sa SetEnding() - /// \sa Valid() - public: bool SetRange(const QualifiedTime &_begin, - const QualifiedTime &_end); - - /// \brief Check if the range is valid. A valid range means that the - /// finish time is guaranteed to be later than or coincident with the - /// start time. - /// \return True if the range is valid, false if invalid. - public: bool Valid() const; - - /// \brief Virtual destructor - public: ~QualifiedTimeRange(); - - /// \internal Implementation class - private: class Implementation; + }; + + ////////////////////////////////////////////////// + /// \brief The QualifiedTimeRange class provides a pair of qualified times + /// that represent a range. This is used to specify a desired time range + /// to the BasicQueryOptions class. + class GZ_TRANSPORT_LOG_VISIBLE QualifiedTimeRange + { + /// \brief Construct a time range. + /// \param[in] _begin The beginning of the time range. + /// \param[in] _end The end of the time range. + /// \sa From() + /// \sa Until() + /// \sa AllTime() + public: QualifiedTimeRange( + const QualifiedTime &_begin, + const QualifiedTime &_end); + + /// \brief Copy constructor + /// \param[in] _other Another QualifiedTimeRange + public: QualifiedTimeRange(const QualifiedTimeRange &_other); + + /// \brief Copy assignment operator + /// \param[in] _other Another QualifiedTimeRange + /// \return Reference to this object + public: QualifiedTimeRange &operator=(const QualifiedTimeRange &_other); + + /// \brief Default move constructor + /// \param[in] _old the instance being moved into this one + public: QualifiedTimeRange(QualifiedTimeRange &&_old); // NOLINT + + /// \brief Default move assignment + /// \return Reference to this object + public: QualifiedTimeRange &operator=( + QualifiedTimeRange &&) = default; // NOLINT(build/c++11) + + /// \brief Equality operator. + /// \param[in] _other Another QualifiedTimeRange + /// \return true if the time ranges represented by each object are + /// equivalent + public: bool operator==(const QualifiedTimeRange &_other) const; + + /// \brief Inequality operator. + /// \param[in] _other Another QualifiedTimeRange + /// \return Opposite of operator==(const QualifiedTimeRange &) + public: bool operator!=(const QualifiedTimeRange &_other) const; + + /// \brief Construct a time range that begins at _begin and never ends. + /// \param[in] _begin The beginning of the time range. + /// \return A time range that begins at _begin and never ends. + public: static QualifiedTimeRange From(const QualifiedTime &_begin); + + /// \brief Construct a time range that ends at _end and has no + /// beginning. + /// \param[in] _end The end of the time range. + /// \return A time range that ends at _end and has no beginning. + public: static QualifiedTimeRange Until(const QualifiedTime &_end); + + /// \brief Construct a time range that has no beginning or end. + /// \return A time range that has no beginning or end. + public: static QualifiedTimeRange AllTime(); + + /// \brief Get a reference to the start time of this range. + /// \return A reference to the start time. + public: const QualifiedTime &Beginning() const; + + /// \brief Get a reference to the end time of this range. + /// \return A reference to the end time. + public: const QualifiedTime &Ending() const; + + /// \brief Set the start time of this range. Passing in an indeterminate + /// QualifiedTime (its default constructor) will tell this range to have + /// no beginning (effectively, it should start at the beginning of the + /// log). + /// \param[in] _begin The start time of this range. + /// \return True if the new range is valid. False if the range is now + /// invalid. The _begin value will be accepted either way. + /// \sa SetRange() + /// \sa Valid() + public: bool SetBeginning(const QualifiedTime &_begin); + + /// \brief Set the finish time of this range. Passing in an + /// indeterminate QualifiedTime (its default constructor) will tell this + /// range to have no end (effectively, it should not stop until the end + /// of the log). + /// \param[in] _end The finish time of this range. + /// \return True if this new range is valid. False if the range is now + /// invalid. The _end value will be accepted either way. + /// \sa SetRange() + /// \sa Valid() + public: bool SetEnding(const QualifiedTime &_end); + + /// \brief Set both endpoints of the range. + /// \param[in] _begin The start time of this range. + /// \param[in] _end The end time of this range. + /// \return True if this new range is valid. False if the range is now + /// invalid. The values for _begin and _end will be accepted either + /// way. + /// \sa SetBeginning() + /// \sa SetEnding() + /// \sa Valid() + public: bool SetRange(const QualifiedTime &_begin, + const QualifiedTime &_end); + + /// \brief Check if the range is valid. A valid range means that the + /// finish time is guaranteed to be later than or coincident with the + /// start time. + /// \return True if the range is valid, false if invalid. + public: bool Valid() const; + + /// \brief Virtual destructor + public: ~QualifiedTimeRange(); + + /// \internal Implementation class + private: class Implementation; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -306,17 +302,14 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal PIMPL pointer - /// We need a custom deleter here due to a compiler bug in MSVC 2017 - private: std::unique_ptr dataPtr; + /// \internal PIMPL pointer + /// We need a custom deleter here due to a compiler bug in MSVC 2017 + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } - } -} - -#endif + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::log +#endif // GZ_TRANSPORT_LOG_QUALIFIEDTIME_HH_ diff --git a/log/include/gz/transport/log/QueryOptions.hh b/log/include/gz/transport/log/QueryOptions.hh index a4ae3a582..5ff9273e3 100644 --- a/log/include/gz/transport/log/QueryOptions.hh +++ b/log/include/gz/transport/log/QueryOptions.hh @@ -30,91 +30,87 @@ #include #include -namespace gz +namespace gz::transport::log { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + ////////////////////////////////////////////////// + /// \brief The QueryOptions interface is used by Log::QueryMessages() to + /// determine which messages are retrieved from the log file. + class GZ_TRANSPORT_LOG_VISIBLE QueryOptions { - namespace log - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - ////////////////////////////////////////////////// - /// \brief The QueryOptions interface is used by Log::QueryMessages() to - /// determine which messages are retrieved from the log file. - class GZ_TRANSPORT_LOG_VISIBLE QueryOptions - { - /// \brief Generate one or more SQL query statements to be used by the - /// log file to produce a Batch of messages. - /// \param[in] _descriptor A Descriptor to help form the SQL statements - /// \return One or more SQL statements. - public: virtual std::vector GenerateStatements( - const Descriptor &_descriptor) const = 0; - - /// \brief Get a standard SQL statement preamble, from the SELECT - /// keyword up to (but not including) the WHERE keyword. This preamble - /// will make sure that the statement is formatted in a way that MsgIter - /// will have the information it needs. - /// - /// Using this statement without modification will query all messages - /// in the log, with no specified order (or fail to compile in the SQL - /// interpreter if you neglect to add a semicolon to the end). Append - /// the output of StandardMessageQueryClose() to ensure that the query - /// output will be ordered by the time each message was received, and - /// that the statement closes with a semicolon. - /// - /// \return The initial clause of a standard QueryOptions SQL statement. - public: static SqlStatement StandardMessageQueryPreamble(); - - /// \brief Get a standard ending to a SQL statement that will instruct - /// the queries to be ordered by the time the messages were received by - /// the logger. It will also end the statement with a semicolon. - /// - /// \return \code{" ORDER BY messages.time_recv;"}\endcode - public: static SqlStatement StandardMessageQueryClose(); - - /// \brief Virtual destructor - public: virtual ~QueryOptions() = default; - }; - - ////////////////////////////////////////////////// - /// \brief Base class which manages the time range settings for the native - /// QueryOptions classes. - class GZ_TRANSPORT_LOG_VISIBLE TimeRangeOption - { - /// \brief Constructor that sets the initial time range option. - /// \param[in] _timeRange The time range. - public: explicit TimeRangeOption(const QualifiedTimeRange &_timeRange); - - /// \brief Copy constructor - /// \param[in] _other Another TimeRangeOption - public: TimeRangeOption(const TimeRangeOption &_other); - - /// \brief Move constructor - /// \param[in] _other Another TimeRangeOption - public: TimeRangeOption(TimeRangeOption &&_other); // NOLINT - - /// \brief Chosen time range - /// \return A mutable reference to the time range that should be queried - /// for. - public: QualifiedTimeRange &TimeRange(); - - /// \brief Chosen time range - /// \return A const reference to the time range that should be queried - /// for. - public: const QualifiedTimeRange &TimeRange() const; - - /// \brief Generate a SQL string to represent the time conditions. - /// This should be appended to a SQL statement after a WHERE keyword. - /// \return A partial SqlStatement that specifies the time conditions - /// that this TimeRangeOption has been set with. - public: SqlStatement GenerateTimeConditions() const; - - /// \brief Destructor - public: ~TimeRangeOption(); - - /// \internal Implementation of this class - private: class Implementation; + /// \brief Generate one or more SQL query statements to be used by the + /// log file to produce a Batch of messages. + /// \param[in] _descriptor A Descriptor to help form the SQL statements + /// \return One or more SQL statements. + public: virtual std::vector GenerateStatements( + const Descriptor &_descriptor) const = 0; + + /// \brief Get a standard SQL statement preamble, from the SELECT + /// keyword up to (but not including) the WHERE keyword. This preamble + /// will make sure that the statement is formatted in a way that MsgIter + /// will have the information it needs. + /// + /// Using this statement without modification will query all messages + /// in the log, with no specified order (or fail to compile in the SQL + /// interpreter if you neglect to add a semicolon to the end). Append + /// the output of StandardMessageQueryClose() to ensure that the query + /// output will be ordered by the time each message was received, and + /// that the statement closes with a semicolon. + /// + /// \return The initial clause of a standard QueryOptions SQL statement. + public: static SqlStatement StandardMessageQueryPreamble(); + + /// \brief Get a standard ending to a SQL statement that will instruct + /// the queries to be ordered by the time the messages were received by + /// the logger. It will also end the statement with a semicolon. + /// + /// \return \code{" ORDER BY messages.time_recv;"}\endcode + public: static SqlStatement StandardMessageQueryClose(); + + /// \brief Virtual destructor + public: virtual ~QueryOptions() = default; + }; + + ////////////////////////////////////////////////// + /// \brief Base class which manages the time range settings for the native + /// QueryOptions classes. + class GZ_TRANSPORT_LOG_VISIBLE TimeRangeOption + { + /// \brief Constructor that sets the initial time range option. + /// \param[in] _timeRange The time range. + public: explicit TimeRangeOption(const QualifiedTimeRange &_timeRange); + + /// \brief Copy constructor + /// \param[in] _other Another TimeRangeOption + public: TimeRangeOption(const TimeRangeOption &_other); + + /// \brief Move constructor + /// \param[in] _other Another TimeRangeOption + public: TimeRangeOption(TimeRangeOption &&_other); // NOLINT + + /// \brief Chosen time range + /// \return A mutable reference to the time range that should be queried + /// for. + public: QualifiedTimeRange &TimeRange(); + + /// \brief Chosen time range + /// \return A const reference to the time range that should be queried + /// for. + public: const QualifiedTimeRange &TimeRange() const; + + /// \brief Generate a SQL string to represent the time conditions. + /// This should be appended to a SQL statement after a WHERE keyword. + /// \return A partial SqlStatement that specifies the time conditions + /// that this TimeRangeOption has been set with. + public: SqlStatement GenerateTimeConditions() const; + + /// \brief Destructor + public: ~TimeRangeOption(); + + /// \internal Implementation of this class + private: class Implementation; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -122,72 +118,72 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal Pointer to the implementation of this class - private: std::unique_ptr dataPtr; + /// \internal Pointer to the implementation of this class + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - - ////////////////////////////////////////////////// - /// \brief Specify a list of topics to query. - class GZ_TRANSPORT_LOG_VISIBLE TopicList final - : public virtual QueryOptions, - public virtual TimeRangeOption - { - /// \brief Query for a list of topics over the specified time range (by - /// default, all time). - /// \param[in] _topics The topics to include - /// \param[in] _timeRange The time range to query over - public: TopicList( - const std::set &_topics = { }, - const QualifiedTimeRange &_timeRange = QualifiedTimeRange::AllTime()); - - /// \brief Factory function that accepts any container type that can be - /// passed through a range-for loop. This will insert the contents of - /// _topics into a blank TopicList and then return it. - /// \param[in] _topics The topics to include - /// \param[in] _timeRange The time range to query over - public: template - static TopicList Create( - const Container &_topics, - const QualifiedTimeRange &_timeRange = QualifiedTimeRange::AllTime()); - - /// \brief Query for a single topic over the specified time range (by - /// default, all time). - /// \param[in] _singleTopic The one topic to query for - /// \param[in] _timeRange The time range to query over - public: TopicList( - const std::string &_singleTopic, - const QualifiedTimeRange &_timeRange = QualifiedTimeRange::AllTime()); - - /// \brief Copy constructor - /// \param[in] _other Another TopicList - public: TopicList(const TopicList &_other); - - /// \brief Move constructor - /// \param[in] _other Another TopicList - public: TopicList(TopicList &&_other); // NOLINT(whitespace/operators) - - /// \brief Topics of this TopicList - /// \return A mutable reference to the topics that this TopicList should - /// query for. - public: std::set &Topics(); - - /// \brief Topics of this TopicList - /// \brief A const reference to the topics that this TopicList should - /// query for. - public: const std::set &Topics() const; - - // Documentation inherited - public: std::vector GenerateStatements( - const Descriptor &_descriptor) const override; - - /// \brief Destructor - public: ~TopicList(); - - /// \internal Implementation for this class - private: class Implementation; + }; + + ////////////////////////////////////////////////// + /// \brief Specify a list of topics to query. + class GZ_TRANSPORT_LOG_VISIBLE TopicList final + : public virtual QueryOptions, + public virtual TimeRangeOption + { + /// \brief Query for a list of topics over the specified time range (by + /// default, all time). + /// \param[in] _topics The topics to include + /// \param[in] _timeRange The time range to query over + public: TopicList( + const std::set &_topics = { }, + const QualifiedTimeRange &_timeRange = QualifiedTimeRange::AllTime()); + + /// \brief Factory function that accepts any container type that can be + /// passed through a range-for loop. This will insert the contents of + /// _topics into a blank TopicList and then return it. + /// \param[in] _topics The topics to include + /// \param[in] _timeRange The time range to query over + public: template + static TopicList Create( + const Container &_topics, + const QualifiedTimeRange &_timeRange = QualifiedTimeRange::AllTime()); + + /// \brief Query for a single topic over the specified time range (by + /// default, all time). + /// \param[in] _singleTopic The one topic to query for + /// \param[in] _timeRange The time range to query over + public: TopicList( + const std::string &_singleTopic, + const QualifiedTimeRange &_timeRange = QualifiedTimeRange::AllTime()); + + /// \brief Copy constructor + /// \param[in] _other Another TopicList + public: TopicList(const TopicList &_other); + + /// \brief Move constructor + /// \param[in] _other Another TopicList + public: TopicList(TopicList &&_other); // NOLINT(whitespace/operators) + + /// \brief Topics of this TopicList + /// \return A mutable reference to the topics that this TopicList should + /// query for. + public: std::set &Topics(); + + /// \brief Topics of this TopicList + /// \brief A const reference to the topics that this TopicList should + /// query for. + public: const std::set &Topics() const; + + // Documentation inherited + public: std::vector GenerateStatements( + const Descriptor &_descriptor) const override; + + /// \brief Destructor + public: ~TopicList(); + + /// \internal Implementation for this class + private: class Implementation; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -195,54 +191,54 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal Pointer to implementation - private: std::unique_ptr dataPtr; + /// \internal Pointer to implementation + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - - ////////////////////////////////////////////////// - /// \brief Specify a pattern of topics to query. - class GZ_TRANSPORT_LOG_VISIBLE TopicPattern final - : public virtual QueryOptions, - public virtual TimeRangeOption - { - /// \brief Query for topics that match a pattern, over a specified time - /// range (by default, all time). - /// \param[in] _pattern The initial pattern that this option should use - /// \param[in] _timeRange The initial range of time for this option - public: TopicPattern( - const std::regex &_pattern, - const QualifiedTimeRange &_timeRange = QualifiedTimeRange::AllTime()); - - /// \brief Copy constructor - /// \param[in] _other Another TopicPattern - public: TopicPattern(const TopicPattern &_other); - - /// \brief Move constructor - /// \param[in] _other Another TopicPattern - public: TopicPattern(TopicPattern &&_other); // NOLINT - - /// \brief Pattern for this option - /// \return A mutable reference to the regular expression pattern that - /// this option will query for. - public: std::regex &Pattern(); - - /// \brief Pattern for this option - /// \return A const reference to the regular expression pattern that - /// this option will query for. - public: const std::regex &Pattern() const; - - // Documentation inherited - public: std::vector GenerateStatements( - const Descriptor &_descriptor) const override; - - /// \brief Destructor - public: ~TopicPattern(); - - /// \internal Implementation of this class - private: class Implementation; + }; + + ////////////////////////////////////////////////// + /// \brief Specify a pattern of topics to query. + class GZ_TRANSPORT_LOG_VISIBLE TopicPattern final + : public virtual QueryOptions, + public virtual TimeRangeOption + { + /// \brief Query for topics that match a pattern, over a specified time + /// range (by default, all time). + /// \param[in] _pattern The initial pattern that this option should use + /// \param[in] _timeRange The initial range of time for this option + public: TopicPattern( + const std::regex &_pattern, + const QualifiedTimeRange &_timeRange = QualifiedTimeRange::AllTime()); + + /// \brief Copy constructor + /// \param[in] _other Another TopicPattern + public: TopicPattern(const TopicPattern &_other); + + /// \brief Move constructor + /// \param[in] _other Another TopicPattern + public: TopicPattern(TopicPattern &&_other); // NOLINT + + /// \brief Pattern for this option + /// \return A mutable reference to the regular expression pattern that + /// this option will query for. + public: std::regex &Pattern(); + + /// \brief Pattern for this option + /// \return A const reference to the regular expression pattern that + /// this option will query for. + public: const std::regex &Pattern() const; + + // Documentation inherited + public: std::vector GenerateStatements( + const Descriptor &_descriptor) const override; + + /// \brief Destructor + public: ~TopicPattern(); + + /// \internal Implementation of this class + private: class Implementation; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -250,42 +246,42 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal Pointer to the implementation - private: std::unique_ptr dataPtr; + /// \internal Pointer to the implementation + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - - ////////////////////////////////////////////////// - /// \brief Query for all the topics. - class GZ_TRANSPORT_LOG_VISIBLE AllTopics final - : public virtual QueryOptions, - public virtual TimeRangeOption - { - /// \brief Query for all the topics over the specified time range (by - /// default, all time). - /// \param[in] _timeRange The initial range of time for this option. - public: explicit AllTopics( - const QualifiedTimeRange &_timeRange = QualifiedTimeRange::AllTime()); - - /// \brief Copy constructor - /// \param[in] _other Another AllTopics - public: AllTopics(const AllTopics &_other); - - /// \brief Move constructor - /// \param[in] _other Another AllTopics - public: AllTopics(AllTopics &&_other); // NOLINT(whitespace/operators) - - // Documentation inherited - public: std::vector GenerateStatements( - const Descriptor &_descriptor) const override; - - /// \brief Destructor - public: ~AllTopics(); - - /// \internal Implementation of this class - private: class Implementation; + }; + + ////////////////////////////////////////////////// + /// \brief Query for all the topics. + class GZ_TRANSPORT_LOG_VISIBLE AllTopics final + : public virtual QueryOptions, + public virtual TimeRangeOption + { + /// \brief Query for all the topics over the specified time range (by + /// default, all time). + /// \param[in] _timeRange The initial range of time for this option. + public: explicit AllTopics( + const QualifiedTimeRange &_timeRange = QualifiedTimeRange::AllTime()); + + /// \brief Copy constructor + /// \param[in] _other Another AllTopics + public: AllTopics(const AllTopics &_other); + + /// \brief Move constructor + /// \param[in] _other Another AllTopics + public: AllTopics(AllTopics &&_other); // NOLINT(whitespace/operators) + + // Documentation inherited + public: std::vector GenerateStatements( + const Descriptor &_descriptor) const override; + + /// \brief Destructor + public: ~AllTopics(); + + /// \internal Implementation of this class + private: class Implementation; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -293,17 +289,13 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal Pointer to the implementation - private: std::unique_ptr dataPtr; + /// \internal Pointer to the implementation + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } - } -} - + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::log #include - -#endif +#endif // GZ_TRANSPORT_LOG_QUERYOPTIONS_HH_ diff --git a/log/include/gz/transport/log/Recorder.hh b/log/include/gz/transport/log/Recorder.hh index ab8891f0b..b3662d67b 100644 --- a/log/include/gz/transport/log/Recorder.hh +++ b/log/include/gz/transport/log/Recorder.hh @@ -27,101 +27,97 @@ #include #include -namespace gz +namespace gz::transport::log { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + enum class RecorderError : int64_t { - namespace log - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - enum class RecorderError : int64_t - { - SUCCESS = 0, - FAILED_TO_OPEN = -1, - FAILED_TO_SUBSCRIBE = -2, - ALREADY_RECORDING = -3, - INVALID_TOPIC = -4, - TOPIC_NOT_FOUND = -5, - ALREADY_SUBSCRIBED_TO_TOPIC = -6, - }; - - /// \brief Records Gazebo Transport topics - /// This class makes it easy to record topics to a log file. - /// Responsibilities: topic name matching, time received tracking, - /// multiple thread safety, subscribing to topics - class GZ_TRANSPORT_LOG_VISIBLE Recorder - { - /// \brief Default constructor - public: Recorder(); - - /// \brief move constructor - /// \param[in] _old the instance being moved into this one - public: Recorder(Recorder &&_old); // NOLINT - - /// \brief destructor - public: ~Recorder(); - - /// \brief Synchronize recording with the given clock. - /// \param[in] _clockIn clock to synchronize and stamp - /// incoming messages with - /// \return SUCCESS if the clock was successfully changed, - /// ALREADY_RECORDING if a recording is already in progress. - /// \remarks Clock lifetime must exceed that of this Recorder. - public: RecorderError Sync(const Clock *_clockIn); - - /// \brief Begin recording topics - /// \param[in] _file path to log file - /// \return NO_ERROR if recording was successfully started. If the file - /// already existed, this will return FAILED_TO_OPEN. - public: RecorderError Start(const std::string &_file); - - /// \brief Stop recording topics. This function will block if there is - /// any data in the internal buffer that has not yet been written to - /// disk. - public: void Stop(); - - /// \brief Add a topic to be recorded (exact match only) - /// \param[in] _topic The exact topic name - /// \note This method attempts to subscribe to the topic immediately. - /// The subscription will be kept until this is destructed. - /// \return NO_ERROR if the subscription was created. - public: RecorderError AddTopic(const std::string &_topic); - - /// \brief Add a topic to be recorded (regex match) - /// \param[in] _topic Pattern to match against topic names - /// \note This method attempts to subscribe to topics immediately. - /// These subscriptions will be kept until this is destructed. - /// New topics that match the pattern will be added as they - /// appear, including while recording is active. - /// \return number of topics subscribed or negative number on error - public: int64_t AddTopic(const std::regex &_topic); - - /// \brief Get the name of the log file. - /// \return The name of the log file, or an empty string if Start has - /// not been successfully called. - public: std::string Filename() const; - - /// \brief Get the set of topics have have been added. - /// \return The set of topic names that have been added using the - /// AddTopic functions. - public: const std::set &Topics() const; - - /// \brief Get the buffer size of the queue that is used to store data - /// from topic callbacks. - /// \return Current buffer size in MB. - public: std::size_t BufferSize() const; - - /// \brief Set the maximum size (in MB) of the buffer that is used to - /// store data from topic callbacks. When the buffer reaches this size, - /// the recorder will start dropping older messages to make room for new - /// ones. - /// \param[in] _size Buffer size in MB - public: void SetBufferSize(std::size_t _size); - - /// \internal Implementation of this class - private: class Implementation; + SUCCESS = 0, + FAILED_TO_OPEN = -1, + FAILED_TO_SUBSCRIBE = -2, + ALREADY_RECORDING = -3, + INVALID_TOPIC = -4, + TOPIC_NOT_FOUND = -5, + ALREADY_SUBSCRIBED_TO_TOPIC = -6, + }; + + /// \brief Records Gazebo Transport topics + /// This class makes it easy to record topics to a log file. + /// Responsibilities: topic name matching, time received tracking, + /// multiple thread safety, subscribing to topics + class GZ_TRANSPORT_LOG_VISIBLE Recorder + { + /// \brief Default constructor + public: Recorder(); + + /// \brief move constructor + /// \param[in] _old the instance being moved into this one + public: Recorder(Recorder &&_old); // NOLINT + + /// \brief destructor + public: ~Recorder(); + + /// \brief Synchronize recording with the given clock. + /// \param[in] _clockIn clock to synchronize and stamp + /// incoming messages with + /// \return SUCCESS if the clock was successfully changed, + /// ALREADY_RECORDING if a recording is already in progress. + /// \remarks Clock lifetime must exceed that of this Recorder. + public: RecorderError Sync(const Clock *_clockIn); + + /// \brief Begin recording topics + /// \param[in] _file path to log file + /// \return NO_ERROR if recording was successfully started. If the file + /// already existed, this will return FAILED_TO_OPEN. + public: RecorderError Start(const std::string &_file); + + /// \brief Stop recording topics. This function will block if there is + /// any data in the internal buffer that has not yet been written to + /// disk. + public: void Stop(); + + /// \brief Add a topic to be recorded (exact match only) + /// \param[in] _topic The exact topic name + /// \note This method attempts to subscribe to the topic immediately. + /// The subscription will be kept until this is destructed. + /// \return NO_ERROR if the subscription was created. + public: RecorderError AddTopic(const std::string &_topic); + + /// \brief Add a topic to be recorded (regex match) + /// \param[in] _topic Pattern to match against topic names + /// \note This method attempts to subscribe to topics immediately. + /// These subscriptions will be kept until this is destructed. + /// New topics that match the pattern will be added as they + /// appear, including while recording is active. + /// \return number of topics subscribed or negative number on error + public: int64_t AddTopic(const std::regex &_topic); + + /// \brief Get the name of the log file. + /// \return The name of the log file, or an empty string if Start has + /// not been successfully called. + public: std::string Filename() const; + + /// \brief Get the set of topics have have been added. + /// \return The set of topic names that have been added using the + /// AddTopic functions. + public: const std::set &Topics() const; + + /// \brief Get the buffer size of the queue that is used to store data + /// from topic callbacks. + /// \return Current buffer size in MB. + public: std::size_t BufferSize() const; + + /// \brief Set the maximum size (in MB) of the buffer that is used to + /// store data from topic callbacks. When the buffer reaches this size, + /// the recorder will start dropping older messages to make room for new + /// ones. + /// \param[in] _size Buffer size in MB + public: void SetBufferSize(std::size_t _size); + + /// \internal Implementation of this class + private: class Implementation; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -129,14 +125,12 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal Pointer to the implementation - private: std::unique_ptr dataPtr; + /// \internal Pointer to the implementation + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } - } -} -#endif + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::log +#endif // GZ_TRANSPORT_LOG_RECORDER_HH_ diff --git a/log/include/gz/transport/log/SqlStatement.hh b/log/include/gz/transport/log/SqlStatement.hh index 02be7ba31..b74fc1833 100644 --- a/log/include/gz/transport/log/SqlStatement.hh +++ b/log/include/gz/transport/log/SqlStatement.hh @@ -25,115 +25,111 @@ #include #include -namespace gz +namespace gz::transport::log { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \brief A class which contains a SQL statement parameter. SqlParameter + /// can be useful for keeping SQL queries sanitized and avoid SQL + /// injection. With C++17, it may be desirable to replace this class with + /// std::variant. + /// + /// These parameter types map directly to the datatypes of SQLite3: + /// https://www.sqlite.org/datatype3.html + class GZ_TRANSPORT_LOG_VISIBLE SqlParameter { - namespace log + /// \brief An enum to indicate which type of parameter this is. + public: enum class ParamType : int { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \brief A class which contains a SQL statement parameter. SqlParameter - /// can be useful for keeping SQL queries sanitized and avoid SQL - /// injection. With C++17, it may be desirable to replace this class with - /// std::variant. - /// - /// These parameter types map directly to the datatypes of SQLite3: - /// https://www.sqlite.org/datatype3.html - class GZ_TRANSPORT_LOG_VISIBLE SqlParameter - { - /// \brief An enum to indicate which type of parameter this is. - public: enum class ParamType : int - { - NULL_TYPE, - INTEGER, - REAL, - TEXT - // TODO(anyone): Consider supporting blob types - }; - - /// \sa Set(std::nullptr_t) - /// \sa SqlParameter(std::nullptr_t) - public: SqlParameter(); - - /// \sa Set(std::nullptr_t) - /// \brief Construct NULL parameter - public: explicit SqlParameter(std::nullptr_t); - - /// \sa Set(int64_t) - /// \brief Construct integer parameter - /// \param[in] _integer an integer - public: explicit SqlParameter(int64_t _integer); - - /// \sa Set(double) - /// \brief Construct real parameter - /// \param[in] _real a real number - public: explicit SqlParameter(double _real); - - /// \sa Set(const std::string &) - /// \brief Construct string parameter - /// \param[in] _string a string - public: explicit SqlParameter(const std::string &_string); - - /// \brief Copy constructor - /// \param[in] _other Another SqlParameter - public: SqlParameter(const SqlParameter &_other); - - /// \brief Move constructor - /// \param[in] _other Another SqlParameter - public: SqlParameter(SqlParameter &&_other); // NOLINT - - /// \brief Copy assignment operator - /// \param[in] _other Another SqlParameter - /// \return This object - public: SqlParameter &operator=(const SqlParameter &_other); - - /// \brief Move assignment operator - /// \param[in] _other Another SqlParameter - /// \return This object - public: SqlParameter &operator=(SqlParameter &&_other); // NOLINT - - /// \brief Set this parameter to a NULL_TYPE. - /// \param[in] _np Pass in a nullptr. - public: void Set(std::nullptr_t _np); - - /// \brief Set this parameter to an INTEGER type. - /// \param[in] _integer The integer value to set this parameter to. - public: void Set(int64_t _integer); - - /// \brief Set this parameter to a floating-point type. - /// \param[in] _real The value to set this parameter to. - public: void Set(double _real); - - /// \brief Set this parameter to a text string. - /// \param[in] _text The value to set this parameter to. - public: void Set(const std::string &_text); - - /// \brief Get the type for this parameter. - /// \return The type for this parameter - public: ParamType Type() const; - - /// \brief Get the integer value of this parameter. - /// \return A pointer to this parameter's integer value, or a nullptr - /// if it does not contain an integer. - public: const int64_t *QueryInteger() const; - - /// \brief Get the floating-point value of this parameter. - /// \return A pointer to this parameter's floating-point value, or a - /// nullptr if it does not contain a REAL value. - public: const double *QueryReal() const; - - /// \brief Get the text value of this paramter. - /// \return A pointer to this parameter's text string, or a nullptr if - /// it does not contain a text string. - public: const std::string *QueryText() const; - - /// \brief Destructor - public: ~SqlParameter(); - - /// \internal Implementation of this class - private: class Implementation; + NULL_TYPE, + INTEGER, + REAL, + TEXT + // TODO(anyone): Consider supporting blob types + }; + + /// \sa Set(std::nullptr_t) + /// \sa SqlParameter(std::nullptr_t) + public: SqlParameter(); + + /// \sa Set(std::nullptr_t) + /// \brief Construct NULL parameter + public: explicit SqlParameter(std::nullptr_t); + + /// \sa Set(int64_t) + /// \brief Construct integer parameter + /// \param[in] _integer an integer + public: explicit SqlParameter(int64_t _integer); + + /// \sa Set(double) + /// \brief Construct real parameter + /// \param[in] _real a real number + public: explicit SqlParameter(double _real); + + /// \sa Set(const std::string &) + /// \brief Construct string parameter + /// \param[in] _string a string + public: explicit SqlParameter(const std::string &_string); + + /// \brief Copy constructor + /// \param[in] _other Another SqlParameter + public: SqlParameter(const SqlParameter &_other); + + /// \brief Move constructor + /// \param[in] _other Another SqlParameter + public: SqlParameter(SqlParameter &&_other); // NOLINT + + /// \brief Copy assignment operator + /// \param[in] _other Another SqlParameter + /// \return This object + public: SqlParameter &operator=(const SqlParameter &_other); + + /// \brief Move assignment operator + /// \param[in] _other Another SqlParameter + /// \return This object + public: SqlParameter &operator=(SqlParameter &&_other); // NOLINT + + /// \brief Set this parameter to a NULL_TYPE. + /// \param[in] _np Pass in a nullptr. + public: void Set(std::nullptr_t _np); + + /// \brief Set this parameter to an INTEGER type. + /// \param[in] _integer The integer value to set this parameter to. + public: void Set(int64_t _integer); + + /// \brief Set this parameter to a floating-point type. + /// \param[in] _real The value to set this parameter to. + public: void Set(double _real); + + /// \brief Set this parameter to a text string. + /// \param[in] _text The value to set this parameter to. + public: void Set(const std::string &_text); + + /// \brief Get the type for this parameter. + /// \return The type for this parameter + public: ParamType Type() const; + + /// \brief Get the integer value of this parameter. + /// \return A pointer to this parameter's integer value, or a nullptr + /// if it does not contain an integer. + public: const int64_t *QueryInteger() const; + + /// \brief Get the floating-point value of this parameter. + /// \return A pointer to this parameter's floating-point value, or a + /// nullptr if it does not contain a REAL value. + public: const double *QueryReal() const; + + /// \brief Get the text value of this paramter. + /// \return A pointer to this parameter's text string, or a nullptr if + /// it does not contain a text string. + public: const std::string *QueryText() const; + + /// \brief Destructor + public: ~SqlParameter(); + + /// \internal Implementation of this class + private: class Implementation; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -141,42 +137,39 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal Pointer to implementation - private: std::unique_ptr dataPtr; + /// \internal Pointer to implementation + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; + }; - /// \brief A statement for a SQL query. These are generated by the - /// QueryOptions class to control how messages get queried from the log. - struct GZ_TRANSPORT_LOG_VISIBLE SqlStatement - { + /// \brief A statement for a SQL query. These are generated by the + /// QueryOptions class to control how messages get queried from the log. + struct GZ_TRANSPORT_LOG_VISIBLE SqlStatement + { #ifdef _WIN32 // Disable warning C4251 which is triggered by // std::* #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Text of the statement - public: std::string statement; + /// \brief Text of the statement + public: std::string statement; - /// \brief Parameters for the statement - public: std::vector parameters; + /// \brief Parameters for the statement + public: std::vector parameters; #ifdef _WIN32 #pragma warning(pop) #endif - /// \brief Append another SQL statement onto the end of this one. - /// _other.statement will be added to the end of this object's statement - /// string, and _other's parameters will be added to this object's - /// vector of parameters. - /// \param[in] _other Another SQL statement. - public: void Append(const SqlStatement &_other); - }; - } - } - } -} - -#endif + /// \brief Append another SQL statement onto the end of this one. + /// _other.statement will be added to the end of this object's statement + /// string, and _other's parameters will be added to this object's + /// vector of parameters. + /// \param[in] _other Another SQL statement. + public: void Append(const SqlStatement &_other); + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::log +#endif // GZ_TRANSPORT_LOG_SQLSTATEMENT_HH_ diff --git a/log/include/gz/transport/log/detail/QueryOptions.hh b/log/include/gz/transport/log/detail/QueryOptions.hh index 4107d2e76..7f94a9ff6 100644 --- a/log/include/gz/transport/log/detail/QueryOptions.hh +++ b/log/include/gz/transport/log/detail/QueryOptions.hh @@ -24,32 +24,25 @@ #include #include -namespace gz +namespace gz::transport::log { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + ////////////////////////////////////////////////// + template + TopicList TopicList::Create( + const Container &_topics, + const QualifiedTimeRange &_timeRange) { - namespace log - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - ////////////////////////////////////////////////// - template - TopicList TopicList::Create( - const Container &_topics, - const QualifiedTimeRange &_timeRange) - { - TopicList tl(std::set(), _timeRange); + TopicList tl(std::set(), _timeRange); - std::set &internalTopics = tl.Topics(); - for (const std::string &topic : _topics) - internalTopics.insert(topic); + std::set &internalTopics = tl.Topics(); + for (const std::string &topic : _topics) + internalTopics.insert(topic); - return tl; - } - } - } + return tl; } -} - -#endif + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::log +#endif // GZ_TRANSPORT_LOG_DETAIL_QUERYOPTIONS_HH_ diff --git a/log/src/Batch.cc b/log/src/Batch.cc index f30db6f19..39545066b 100644 --- a/log/src/Batch.cc +++ b/log/src/Batch.cc @@ -23,8 +23,9 @@ #include "MsgIterPrivate.hh" #include "raii-sqlite3.hh" -using namespace gz::transport; -using namespace gz::transport::log; + +namespace gz::transport::log +{ ////////////////////////////////////////////////// BatchPrivate::BatchPrivate(const std::shared_ptr &_db, @@ -89,3 +90,4 @@ Batch::Batch(std::unique_ptr &&_pimpl) // NOLINT(build/c++11) : dataPtr(std::move(_pimpl)) { } +} // namespace gz::transport::log diff --git a/log/src/BatchPrivate.hh b/log/src/BatchPrivate.hh index 9521bad5b..ae71b3745 100644 --- a/log/src/BatchPrivate.hh +++ b/log/src/BatchPrivate.hh @@ -23,12 +23,15 @@ #include "gz/transport/log/SqlStatement.hh" #include "raii-sqlite3.hh" -using namespace gz::transport; -using namespace gz::transport::log; +namespace gz::transport::log +{ +// Inline bracket to help doxygen filtering. +inline namespace GZ_TRANSPORT_VERSION_NAMESPACE +{ /// \brief Private implementation for Batch /// \internal -class gz::transport::log::BatchPrivate +class BatchPrivate { /// \brief constructor /// \param[in] _db an open sqlite3 database handle wrapper @@ -46,5 +49,6 @@ class gz::transport::log::BatchPrivate /// \brief SQLite3 database pointer wrapper public: std::shared_ptr db; }; - -#endif +} // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::log +#endif // GZ_TRANSPORT_LOG_BATCHPRIVATE_HH_ diff --git a/log/src/Console.cc b/log/src/Console.cc index d9fe01546..7ecc6c930 100644 --- a/log/src/Console.cc +++ b/log/src/Console.cc @@ -17,16 +17,10 @@ #include "Console.hh" -namespace gz -{ -namespace transport -{ -namespace log +namespace gz::transport::log { inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { int __verbosity = 1; } -} -} -} +} // namespace gz::transport::log diff --git a/log/src/Console.hh b/log/src/Console.hh index 50bcd0d09..3e0d00bda 100644 --- a/log/src/Console.hh +++ b/log/src/Console.hh @@ -22,18 +22,12 @@ #include -namespace gz +namespace gz::transport::log { - namespace transport - { - namespace log - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - extern int __verbosity; - } - } + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + extern int __verbosity; } } diff --git a/log/src/Descriptor.cc b/log/src/Descriptor.cc index b28aeb812..e750cf4d8 100644 --- a/log/src/Descriptor.cc +++ b/log/src/Descriptor.cc @@ -20,8 +20,8 @@ #include #include -using namespace gz::transport::log; - +namespace gz::transport::log +{ ////////////////////////////////////////////////// void Descriptor::Implementation::Reset(const TopicKeyMap &_columns) { @@ -87,3 +87,4 @@ Descriptor::Descriptor(Descriptor &&_orig) // NOLINT(build/c++11) { // Do nothing } +} // namespace gz::transport::log diff --git a/log/src/Descriptor.hh b/log/src/Descriptor.hh index 63b38cc54..b5847436f 100644 --- a/log/src/Descriptor.hh +++ b/log/src/Descriptor.hh @@ -24,59 +24,55 @@ #include -namespace gz +namespace gz::transport::log { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \brief A representation of the information that defines a topic row + /// \note We export the symbols for this class so it can be used in + /// UNIT_Descriptor_TEST + struct GZ_TRANSPORT_LOG_VISIBLE TopicKey { - namespace log - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \brief A representation of the information that defines a topic row - /// \note We export the symbols for this class so it can be used in - /// UNIT_Descriptor_TEST - struct GZ_TRANSPORT_LOG_VISIBLE TopicKey - { #ifdef _WIN32 // Disable warning C4251 which is triggered by // std::unique_ptr #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief The name of the topic - public: std::string topic; + /// \brief The name of the topic + public: std::string topic; - /// \brief The message type name published on the topic - public: std::string type; + /// \brief The message type name published on the topic + public: std::string type; #ifdef _WIN32 #pragma warning(pop) #endif - /// \brief Equality operator. Needed for std::unordered_map - /// \param[in] _other Another TopicKey - /// \return true if equal - inline bool operator==(const TopicKey &_other) const - { - return (this->topic == _other.topic && - this->type == _other.type); - } - }; + /// \brief Equality operator. Needed for std::unordered_map + /// \param[in] _other Another TopicKey + /// \return true if equal + inline bool operator==(const TopicKey &_other) const + { + return (this->topic == _other.topic && + this->type == _other.type); + } + }; - /// \brief A map from the (topic, message type) of a topic to its integer - /// key in the database. - using TopicKeyMap = std::unordered_map; + /// \brief A map from the (topic, message type) of a topic to its integer + /// key in the database. + using TopicKeyMap = std::unordered_map; - /// \brief Implementation of the Descriptor class - /// \note We export the symbols for this class so it can be used in - /// UNIT_Descriptor_TEST - class GZ_TRANSPORT_LOG_VISIBLE Descriptor::Implementation - { - /// \internal Reset this descriptor. This should only be called by the - /// Log class, when it is generating a new Descriptor after opening a - /// new file. - /// \param[in] _topics The map of topics that the log contains. - public: void Reset(const TopicKeyMap &_topics); + /// \brief Implementation of the Descriptor class + /// \note We export the symbols for this class so it can be used in + /// UNIT_Descriptor_TEST + class GZ_TRANSPORT_LOG_VISIBLE Descriptor::Implementation + { + /// \internal Reset this descriptor. This should only be called by the + /// Log class, when it is generating a new Descriptor after opening a + /// new file. + /// \param[in] _topics The map of topics that the log contains. + public: void Reset(const TopicKeyMap &_topics); #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -84,19 +80,17 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \internal \sa Descriptor::TopicsToMsgTypesToId() - public: NameToMap topicsToMsgTypesToId; + /// \internal \sa Descriptor::TopicsToMsgTypesToId() + public: NameToMap topicsToMsgTypesToId; - /// \internal \sa Descriptor::MsgTypesToTopicsToId() - public: NameToMap msgTypesToTopicsToId; + /// \internal \sa Descriptor::MsgTypesToTopicsToId() + public: NameToMap msgTypesToTopicsToId; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } - } -} + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::log ////////////////////////////////////////////////// /// \brief Allow a TopicKey to be used as a key in a std::unordered_map @@ -111,6 +105,5 @@ namespace std { + std::hash()(_key.type); } }; -} - -#endif +} // namespace std +#endif // GZ_TRANSPORT_LOG_SRC_DESCRIPTOR_HH_ diff --git a/log/src/Log.cc b/log/src/Log.cc index bf39a5d5b..71e798af7 100644 --- a/log/src/Log.cc +++ b/log/src/Log.cc @@ -35,11 +35,11 @@ #include "Descriptor.hh" #include "raii-sqlite3.hh" -using namespace gz::transport; -using namespace gz::transport::log; +namespace gz::transport::log +{ /// \brief Private implementation -class gz::transport::log::Log::Implementation +class Log::Implementation { /// \internal \sa Log::Descriptor() public: const log::Descriptor *Descriptor() const; @@ -717,3 +717,4 @@ std::string Log::Filename() const { return this->dataPtr->filename; } +} // namespace gz::transport::log diff --git a/log/src/Message.cc b/log/src/Message.cc index 6a4f2484b..e18e0cda7 100644 --- a/log/src/Message.cc +++ b/log/src/Message.cc @@ -20,11 +20,14 @@ #include "gz/transport/log/Message.hh" -using namespace gz::transport; -using namespace gz::transport::log; using namespace std::chrono_literals; -class gz::transport::log::MessagePrivate +namespace gz::transport::log +{ +// Inline bracket to help doxygen filtering. +inline namespace GZ_TRANSPORT_VERSION_NAMESPACE +{ +class MessagePrivate { /// \brief Time received public: std::chrono::nanoseconds timeReceived = 0ns; @@ -47,6 +50,7 @@ class gz::transport::log::MessagePrivate /// \brief Length of message type public: std::size_t typeLen = 0; }; +} // namespace GZ_TRANSPORT_VERSION_NAMESPACE ////////////////////////////////////////////////// Message::Message() @@ -99,3 +103,4 @@ const std::chrono::nanoseconds &Message::TimeReceived() const { return this->dataPtr->timeReceived; } +} // namespace gz::transport::log diff --git a/log/src/MsgIter.cc b/log/src/MsgIter.cc index d3030e562..8d4cbdbe9 100644 --- a/log/src/MsgIter.cc +++ b/log/src/MsgIter.cc @@ -25,9 +25,8 @@ #include "MsgIterPrivate.hh" #include "raii-sqlite3.hh" -using namespace gz::transport; -using namespace gz::transport::log; - +namespace gz::transport::log +{ ////////////////////////////////////////////////// MsgIterPrivate::MsgIterPrivate() { @@ -245,3 +244,4 @@ const Message *MsgIter::operator->() const { return this->dataPtr->message.get(); } +} // namespace gz::transport::log diff --git a/log/src/MsgIterPrivate.hh b/log/src/MsgIterPrivate.hh index 55e543376..b8e84f2ee 100644 --- a/log/src/MsgIterPrivate.hh +++ b/log/src/MsgIterPrivate.hh @@ -25,14 +25,7 @@ #include "gz/transport/log/SqlStatement.hh" #include "raii-sqlite3.hh" -using namespace gz::transport; -using namespace gz::transport::log; - -namespace gz -{ -namespace transport -{ -namespace log +namespace gz::transport::log { // Inline bracket to help doxygen filtering. inline namespace GZ_TRANSPORT_VERSION_NAMESPACE @@ -74,8 +67,6 @@ inline namespace GZ_TRANSPORT_VERSION_NAMESPACE /// \brief the message this iterator is at public: std::unique_ptr message; }; -} -} -} -} -#endif +} // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::log +#endif // GZ_TRANSPORT_LOG_MSGITERPRIVATE_HH_ diff --git a/log/src/Playback.cc b/log/src/Playback.cc index b603247dd..30a406c1c 100644 --- a/log/src/Playback.cc +++ b/log/src/Playback.cc @@ -34,18 +34,17 @@ #include "build_config.hh" #include "raii-sqlite3.hh" -using namespace gz::transport; -using namespace gz::transport::log; - // We check whether sqlite3 is potentially threadsafe. Note that this only // knows whether sqlite3 was compiled with multi-threading capabilities. It // might not catch changes to sqlite3's runtime settings. // See: https://www.sqlite.org/threadsafe.html static const bool kSqlite3Threadsafe = (sqlite3_threadsafe() != 0); +namespace gz::transport::log +{ ////////////////////////////////////////////////// /// \brief Private implementation of Playback -class gz::transport::log::Playback::Implementation +class Playback::Implementation { /// \brief Constructor. Creates and initializes the log file /// \param[in] _file The full path of the file to open @@ -810,3 +809,4 @@ PlaybackHandle::PlaybackHandle( { // Do nothing } +} // namespace gz::transport::log diff --git a/log/src/QualifiedTime.cc b/log/src/QualifiedTime.cc index ce2203b18..fdcdfe82f 100644 --- a/log/src/QualifiedTime.cc +++ b/log/src/QualifiedTime.cc @@ -19,11 +19,11 @@ #include -using namespace gz::transport::log; - +namespace gz::transport::log +{ ////////////////////////////////////////////////// /// \internal Implementation for QualifiedTime -class gz::transport::log::QualifiedTime::Implementation +class QualifiedTime::Implementation { /// \internal \sa QualifiedTime(const std::chrono::nanoseconds&, Qualifier) public: Implementation(const Time &_time, @@ -392,3 +392,4 @@ QualifiedTimeRange::~QualifiedTimeRange() { // Destroy pimpl } +} // namespace gz::transport::log diff --git a/log/src/QueryOptions.cc b/log/src/QueryOptions.cc index 8d1a3c3f0..7ccb1d86e 100644 --- a/log/src/QueryOptions.cc +++ b/log/src/QueryOptions.cc @@ -23,15 +23,14 @@ #include -using namespace gz::transport; -using namespace gz::transport::log; - +namespace +{ ////////////////////////////////////////////////// /// \brief Append a topic ID condition clause that specifies a list of Topic IDs /// \param[in,out] _sql The SqlStatement to append the clause to /// \param[in] _ids The vector of Topic IDs to include in the list -static void AppendTopicListClause( - SqlStatement &_sql, const std::vector &_ids) +void AppendTopicListClause( + gz::transport::log::SqlStatement &_sql, const std::vector &_ids) { _sql.statement += "topic_id in ("; bool first = true; @@ -52,7 +51,10 @@ static void AppendTopicListClause( _sql.statement += ")"; } +} // namespace +namespace gz::transport::log +{ ////////////////////////////////////////////////// SqlStatement QueryOptions::StandardMessageQueryPreamble() { @@ -444,3 +446,4 @@ AllTopics::~AllTopics() { // Destroy the pimpl } +} // namespace gz::transport::log diff --git a/log/src/Recorder.cc b/log/src/Recorder.cc index 11b83040d..64d6e4cce 100644 --- a/log/src/Recorder.cc +++ b/log/src/Recorder.cc @@ -40,11 +40,11 @@ #include "raii-sqlite3.hh" #include "build_config.hh" -using namespace gz::transport; -using namespace gz::transport::log; +namespace gz::transport::log +{ /// \brief Private implementation -class gz::transport::log::Recorder::Implementation +class Recorder::Implementation { /// \brief Data type stored in dataQueue public: struct LogData @@ -548,3 +548,4 @@ void Recorder::SetBufferSize(std::size_t _size) // Shift by 20 to convert to bytes this->dataPtr->maxBufferSize = _size << 20; } +} // namespace gz::transport::log diff --git a/log/src/SqlStatement.cc b/log/src/SqlStatement.cc index da87018b1..ef7996ae3 100644 --- a/log/src/SqlStatement.cc +++ b/log/src/SqlStatement.cc @@ -20,8 +20,8 @@ #include -using namespace gz::transport::log; - +namespace gz::transport::log +{ ////////////////////////////////////////////////// class SqlParameter::Implementation { @@ -227,3 +227,4 @@ void SqlStatement::Append(const SqlStatement &_other) for (const SqlParameter &p : _other.parameters) this->parameters.push_back(p); } +} // namespace gz::transport::log diff --git a/log/src/raii-sqlite3.cc b/log/src/raii-sqlite3.cc index 298e0662f..6da039c94 100644 --- a/log/src/raii-sqlite3.cc +++ b/log/src/raii-sqlite3.cc @@ -22,8 +22,8 @@ #include "Console.hh" #include "raii-sqlite3.hh" -using namespace raii_sqlite3; - +namespace raii_sqlite3 +{ ////////////////////////////////////////////////// Database::Database(const std::string &_path, int _flags) { @@ -125,3 +125,4 @@ Statement::operator bool() const { return this->handle != nullptr; } +} // namespace raii_sqlite3 diff --git a/log/src/raii-sqlite3.hh b/log/src/raii-sqlite3.hh index f4d249345..36680ac90 100644 --- a/log/src/raii-sqlite3.hh +++ b/log/src/raii-sqlite3.hh @@ -73,6 +73,5 @@ namespace raii_sqlite3 /// \brief the pointer this is wrapping protected: sqlite3_stmt *handle = nullptr; }; -} - -#endif +} // namespace raii_sqlite3 +#endif // GZ_TRANSPORT_LOG_RAIISQLITE3_HH_ diff --git a/parameters/include/gz/transport/parameters/Client.hh b/parameters/include/gz/transport/parameters/Client.hh index cfcadf7b2..ee9f684fa 100644 --- a/parameters/include/gz/transport/parameters/Client.hh +++ b/parameters/include/gz/transport/parameters/Client.hh @@ -30,76 +30,71 @@ #include "gz/transport/parameters/Export.hh" #include "gz/transport/parameters/Interface.hh" -namespace gz +namespace gz::transport::parameters { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + + struct ParametersClientPrivate; + + /// \brief Allow to get, set, declare or list parameters + /// \brief in a remote registry. + class GZ_TRANSPORT_PARAMETERS_VISIBLE ParametersClient + : public ParametersInterface { - namespace parameters - { - - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - - struct ParametersClientPrivate; - - /// \brief Allow to get, set, declare or list parameters - /// \brief in a remote registry. - class GZ_TRANSPORT_PARAMETERS_VISIBLE ParametersClient - : public ParametersInterface - { - /// \brief Constructor. - /// \param[in] _serverNamespace Namespace of the parameters registry - /// services. The client will send requests to: - /// * /${_serverNamespace}/get_parameter - /// * /${_serverNamespace}/list_parameters - /// * /${_serverNamespace}/set_parameter - /// * /${_serverNamespace}/declare_parameter - /// \param[in] _timeoutMs Time to wait for the server to respond. - public: ParametersClient( - const std::string & _serverNamespace = "", - unsigned int _timeoutMs = kDefaultTimeoutMs); - - /// \brief Destructor. - public: ~ParametersClient(); - - /// \brief No copy constructor. - public: ParametersClient(const ParametersClient &) = delete; - /// \brief No copy assignment. - public: ParametersClient & operator=( - const ParametersClient &) = delete; - /// \brief Default move constructor. - public: ParametersClient(ParametersClient &&); - /// \brief Default move assignment. - public: ParametersClient & operator=( - ParametersClient &&); - - /// \brief Declare a new parameter. - /// See ParametersInterface::DeclareParameter(). - public: ParameterResult DeclareParameter( - const std::string & _parameterName, - const google::protobuf::Message & _msg) final; - - /// \brief Request the value of a parameter. - /// See ParametersInterface::Parameter(). - public: ParameterResult Parameter( - const std::string & _parameterName, - google::protobuf::Message & _parameter) const final; - - public: ParameterResult Parameter( - const std::string & _parameterName, - std::unique_ptr & _parameter) const final; - - /// \brief Set the value of a parameter. - /// See ParametersInterface::SetParameter(). - public: ParameterResult SetParameter( - const std::string & _parameterName, - const google::protobuf::Message & _msg) final; - - /// \brief List all parameters. - /// \return Protobuf message with a list of all declared parameter - /// names and their types. - public: gz::msgs::ParameterDeclarations - ListParameters() const final; + /// \brief Constructor. + /// \param[in] _serverNamespace Namespace of the parameters registry + /// services. The client will send requests to: + /// * /${_serverNamespace}/get_parameter + /// * /${_serverNamespace}/list_parameters + /// * /${_serverNamespace}/set_parameter + /// * /${_serverNamespace}/declare_parameter + /// \param[in] _timeoutMs Time to wait for the server to respond. + public: ParametersClient( + const std::string & _serverNamespace = "", + unsigned int _timeoutMs = kDefaultTimeoutMs); + + /// \brief Destructor. + public: ~ParametersClient(); + + /// \brief No copy constructor. + public: ParametersClient(const ParametersClient &) = delete; + /// \brief No copy assignment. + public: ParametersClient & operator=( + const ParametersClient &) = delete; + /// \brief Default move constructor. + public: ParametersClient(ParametersClient &&); + /// \brief Default move assignment. + public: ParametersClient & operator=( + ParametersClient &&); + + /// \brief Declare a new parameter. + /// See ParametersInterface::DeclareParameter(). + public: ParameterResult DeclareParameter( + const std::string & _parameterName, + const google::protobuf::Message & _msg) final; + + /// \brief Request the value of a parameter. + /// See ParametersInterface::Parameter(). + public: ParameterResult Parameter( + const std::string & _parameterName, + google::protobuf::Message & _parameter) const final; + + public: ParameterResult Parameter( + const std::string & _parameterName, + std::unique_ptr & _parameter) const final; + + /// \brief Set the value of a parameter. + /// See ParametersInterface::SetParameter(). + public: ParameterResult SetParameter( + const std::string & _parameterName, + const google::protobuf::Message & _msg) final; + + /// \brief List all parameters. + /// \return Protobuf message with a list of all declared parameter + /// names and their types. + public: gz::msgs::ParameterDeclarations + ListParameters() const final; #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -107,17 +102,14 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Pointer to implementation. - private: std::unique_ptr dataPtr; + /// \brief Pointer to implementation. + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - private: constexpr static inline unsigned int kDefaultTimeoutMs = 5000; - }; - } - } - } -} - -#endif + private: constexpr static inline unsigned int kDefaultTimeoutMs = 5000; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::parameters +#endif // GZ_TRANSPORT_PARAMETERS_CLIENT_HH_ diff --git a/parameters/include/gz/transport/parameters/Interface.hh b/parameters/include/gz/transport/parameters/Interface.hh index 1e3011daf..a3c18a573 100644 --- a/parameters/include/gz/transport/parameters/Interface.hh +++ b/parameters/include/gz/transport/parameters/Interface.hh @@ -31,82 +31,75 @@ #include "gz/transport/parameters/result.hh" #include "gz/transport/parameters/Export.hh" -namespace gz +namespace gz::transport::parameters { - namespace transport - { - namespace parameters - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - - /// \brief Common interface, implemented by ParametersRegistry - /// (local updates) and by ParametersClients (remote requests). - class GZ_TRANSPORT_PARAMETERS_VISIBLE ParametersInterface - { - /// Default virtual destructor. - public: virtual ~ParametersInterface() = default; + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - /// \brief Declare a new parameter. - /// \param[in] _parameterName Name of the parameter to be declared. - /// \param[in] _msg Protobuf message to be used as the initial - /// parameter value. - /// \return A ParameterResult return code, can return error types: - /// - ParameterResultType::AlreadyDeclared if the parameter was already - /// declared. - /// - ParameterResultType::InvalidType if the parameter type is not - /// valid. - public: virtual ParameterResult DeclareParameter( - const std::string & _parameterName, - const google::protobuf::Message & _msg) = 0; + /// \brief Common interface, implemented by ParametersRegistry + /// (local updates) and by ParametersClients (remote requests). + class GZ_TRANSPORT_PARAMETERS_VISIBLE ParametersInterface + { + /// Default virtual destructor. + public: virtual ~ParametersInterface() = default; - /// \brief Request the value of a parameter. - /// \param[in] _parameterName Name of the parameter to be requested. - /// \param[out] _parameter Output were the parameter value will be set. - /// \return A ParameterResult return code, can return error types: - /// - ParameterResultType::NotDeclared if the parameter was not - /// declared. - /// - ParameterResultType::InvalidType if the parameter type was - /// invalid. - /// - ParameterResultType::Unexpected, if an unexpected error happened. - public: virtual ParameterResult Parameter( - const std::string & _parameterName, - google::protobuf::Message & _parameter) const = 0; + /// \brief Declare a new parameter. + /// \param[in] _parameterName Name of the parameter to be declared. + /// \param[in] _msg Protobuf message to be used as the initial + /// parameter value. + /// \return A ParameterResult return code, can return error types: + /// - ParameterResultType::AlreadyDeclared if the parameter was already + /// declared. + /// - ParameterResultType::InvalidType if the parameter type is not + /// valid. + public: virtual ParameterResult DeclareParameter( + const std::string & _parameterName, + const google::protobuf::Message & _msg) = 0; - /// \brief Request the value of a parameter. - /// Similar to the other overload, but it allocates a message of the - /// right type. - /// - /// \param[in] _parameterName Name of the parameter to be requested. - /// \param[out] _parameter Output were the parameter value will be set. - /// \return A ParameterResult return code, can return error types: - /// - ParameterResultType::NotDeclared if the parameter was not - /// declared. - /// - ParameterResultType::Unexpected, if an unexpected error happened. - public: virtual ParameterResult Parameter( - const std::string & _parameterName, - std::unique_ptr & _parameter) const = 0; + /// \brief Request the value of a parameter. + /// \param[in] _parameterName Name of the parameter to be requested. + /// \param[out] _parameter Output were the parameter value will be set. + /// \return A ParameterResult return code, can return error types: + /// - ParameterResultType::NotDeclared if the parameter was not + /// declared. + /// - ParameterResultType::InvalidType if the parameter type was + /// invalid. + /// - ParameterResultType::Unexpected, if an unexpected error happened. + public: virtual ParameterResult Parameter( + const std::string & _parameterName, + google::protobuf::Message & _parameter) const = 0; - /// \brief Set the value of a parameter. - /// \param[in] _parameterName Name of the parameter to be set. - /// \param[in] _msg Protobuf message to be used as the parameter value. - /// \return A ParameterResult return code, can return error types: - /// - ParameterResultType::NotDeclared if the parameter was not - /// declared. - /// - ParameterResultType::InvalidType if the parameter type was - /// invalid. - public: virtual ParameterResult SetParameter( - const std::string & _parameterName, - const google::protobuf::Message & _msg) = 0; + /// \brief Request the value of a parameter. + /// Similar to the other overload, but it allocates a message of the + /// right type. + /// + /// \param[in] _parameterName Name of the parameter to be requested. + /// \param[out] _parameter Output were the parameter value will be set. + /// \return A ParameterResult return code, can return error types: + /// - ParameterResultType::NotDeclared if the parameter was not + /// declared. + /// - ParameterResultType::Unexpected, if an unexpected error happened. + public: virtual ParameterResult Parameter( + const std::string & _parameterName, + std::unique_ptr & _parameter) const = 0; - /// \brief List all existing parameters. - /// \return The name and types of existing parameters. - public: virtual gz::msgs::ParameterDeclarations - ListParameters() const = 0; - }; - } - } - } -} + /// \brief Set the value of a parameter. + /// \param[in] _parameterName Name of the parameter to be set. + /// \param[in] _msg Protobuf message to be used as the parameter value. + /// \return A ParameterResult return code, can return error types: + /// - ParameterResultType::NotDeclared if the parameter was not + /// declared. + /// - ParameterResultType::InvalidType if the parameter type was + /// invalid. + public: virtual ParameterResult SetParameter( + const std::string & _parameterName, + const google::protobuf::Message & _msg) = 0; -#endif + /// \brief List all existing parameters. + /// \return The name and types of existing parameters. + public: virtual gz::msgs::ParameterDeclarations + ListParameters() const = 0; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::parameters +#endif // GZ_TRANSPORT_PARAMETERS_INTERFACE_HH_ diff --git a/parameters/include/gz/transport/parameters/Registry.hh b/parameters/include/gz/transport/parameters/Registry.hh index 63b8fd521..23096a330 100644 --- a/parameters/include/gz/transport/parameters/Registry.hh +++ b/parameters/include/gz/transport/parameters/Registry.hh @@ -31,99 +31,95 @@ #include "gz/transport/parameters/Export.hh" #include "gz/transport/parameters/Interface.hh" -namespace gz +namespace gz::transport::parameters { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + + struct ParametersRegistryPrivate; + + /// \brief Provides a parameter registry. + /// Parameters can be declared, get or set in the registry. + /// It also provides services, so the parameters can be get, set or + /// listed from other processes. + /// + /// Provided services: + /// * /${_parametersServicesNamespace}/get_parameter + /// * /${_parametersServicesNamespace}/list_parameters + /// * /${_parametersServicesNamespace}/set_parameter + /// * /${_parametersServicesNamespace}/declare_parameter + class GZ_TRANSPORT_PARAMETERS_VISIBLE ParametersRegistry + : public ParametersInterface { - namespace parameters - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - - struct ParametersRegistryPrivate; - - /// \brief Provides a parameter registry. - /// Parameters can be declared, get or set in the registry. - /// It also provides services, so the parameters can be get, set or - /// listed from other processes. - /// - /// Provided services: - /// * /${_parametersServicesNamespace}/get_parameter - /// * /${_parametersServicesNamespace}/list_parameters - /// * /${_parametersServicesNamespace}/set_parameter - /// * /${_parametersServicesNamespace}/declare_parameter - class GZ_TRANSPORT_PARAMETERS_VISIBLE ParametersRegistry - : public ParametersInterface - { - /// \brief Constructor. - /// \param[in] _parametersServicesNamespace Namespace that will be used - /// in all the created services names. - public: explicit ParametersRegistry( - const std::string & _parametersServicesNamespace); - - /// \brief Destructor. - public: ~ParametersRegistry(); - - /// \brief No copy constructor. - public: ParametersRegistry(const ParametersRegistry &) = delete; - /// \brief No copy assignment. - public: ParametersRegistry & - operator=(const ParametersRegistry &) = delete; - /// \brief Default move constructor. - public: ParametersRegistry(ParametersRegistry &&); - /// \brief Default move assignment. - public: ParametersRegistry & - operator=(ParametersRegistry &&); - - /// \brief Declare a new parameter. - /// See ParametersInterface::DeclareParameter(). - public: ParameterResult DeclareParameter( - const std::string & _parameterName, - const google::protobuf::Message & _msg) final; - - /// \brief Request the value of a parameter. - /// See ParametersInterface::Parameter(). - public: ParameterResult Parameter( - const std::string & _parameterName, - google::protobuf::Message & _parameter) const final; - - public: ParameterResult Parameter( - const std::string & _parameterName, - std::unique_ptr & _parameter) const final; - - /// \brief Set the value of a parameter. - /// See ParametersInterface::SetParameter(). - public: ParameterResult SetParameter( - const std::string & _parameterName, - const google::protobuf::Message & _msg) final; - - /// \brief List all parameters. - /// \return Protobuf message with a list of all declared parameter - /// names and their types. - public: gz::msgs::ParameterDeclarations - ListParameters() const final; - - /// \brief Declare a new parameter. - /// \param[in] _parameterName Name of the parameter. - /// \param[in] _initialValue The initial value of the parameter. - /// The parameter type will be deduced from the type of the message. - /// \throw std::invalid_argument if `_initialValue` is `nullptr`. - /// \throw ParameterAlreadyDeclaredException if a parameter with the - /// same name was declared before. - public: ParameterResult DeclareParameter( - const std::string & _parameterName, - std::unique_ptr _initialValue); - - /// \brief Set the value of a parameter. - /// \param[in] _parameterName Name of the parameter to set. - /// \param[in] _value The value of the parameter. - /// \throw ParameterNotDeclaredException if a parameter of that name - /// was not declared before. - /// \throw ParameterInvalidTypeException if the type does not match - /// the type of the parameter when it was declared. - public: ParameterResult SetParameter( - const std::string & _parameterName, - std::unique_ptr _value); + /// \brief Constructor. + /// \param[in] _parametersServicesNamespace Namespace that will be used + /// in all the created services names. + public: explicit ParametersRegistry( + const std::string & _parametersServicesNamespace); + + /// \brief Destructor. + public: ~ParametersRegistry(); + + /// \brief No copy constructor. + public: ParametersRegistry(const ParametersRegistry &) = delete; + /// \brief No copy assignment. + public: ParametersRegistry & + operator=(const ParametersRegistry &) = delete; + /// \brief Default move constructor. + public: ParametersRegistry(ParametersRegistry &&); + /// \brief Default move assignment. + public: ParametersRegistry & + operator=(ParametersRegistry &&); + + /// \brief Declare a new parameter. + /// See ParametersInterface::DeclareParameter(). + public: ParameterResult DeclareParameter( + const std::string & _parameterName, + const google::protobuf::Message & _msg) final; + + /// \brief Request the value of a parameter. + /// See ParametersInterface::Parameter(). + public: ParameterResult Parameter( + const std::string & _parameterName, + google::protobuf::Message & _parameter) const final; + + public: ParameterResult Parameter( + const std::string & _parameterName, + std::unique_ptr & _parameter) const final; + + /// \brief Set the value of a parameter. + /// See ParametersInterface::SetParameter(). + public: ParameterResult SetParameter( + const std::string & _parameterName, + const google::protobuf::Message & _msg) final; + + /// \brief List all parameters. + /// \return Protobuf message with a list of all declared parameter + /// names and their types. + public: gz::msgs::ParameterDeclarations + ListParameters() const final; + + /// \brief Declare a new parameter. + /// \param[in] _parameterName Name of the parameter. + /// \param[in] _initialValue The initial value of the parameter. + /// The parameter type will be deduced from the type of the message. + /// \throw std::invalid_argument if `_initialValue` is `nullptr`. + /// \throw ParameterAlreadyDeclaredException if a parameter with the + /// same name was declared before. + public: ParameterResult DeclareParameter( + const std::string & _parameterName, + std::unique_ptr _initialValue); + + /// \brief Set the value of a parameter. + /// \param[in] _parameterName Name of the parameter to set. + /// \param[in] _value The value of the parameter. + /// \throw ParameterNotDeclaredException if a parameter of that name + /// was not declared before. + /// \throw ParameterInvalidTypeException if the type does not match + /// the type of the parameter when it was declared. + public: ParameterResult SetParameter( + const std::string & _parameterName, + std::unique_ptr _value); #ifdef _WIN32 // Disable warning C4251 which is triggered by @@ -131,15 +127,12 @@ namespace gz #pragma warning(push) #pragma warning(disable: 4251) #endif - /// \brief Pointer to implementation. - private: std::unique_ptr dataPtr; + /// \brief Pointer to implementation. + private: std::unique_ptr dataPtr; #ifdef _WIN32 #pragma warning(pop) #endif - }; - } - } - } -} - -#endif + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::parameters +#endif // GZ_TRANSPORT_PARAMETERS_REGISTRY_HH_ diff --git a/parameters/include/gz/transport/parameters/result.hh b/parameters/include/gz/transport/parameters/result.hh index 8bc35c19f..5cc515d41 100644 --- a/parameters/include/gz/transport/parameters/result.hh +++ b/parameters/include/gz/transport/parameters/result.hh @@ -24,78 +24,71 @@ #include "gz/transport/config.hh" #include "gz/transport/parameters/Export.hh" -namespace gz +namespace gz::transport::parameters { - namespace transport - { - namespace parameters - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - - /// \brief Possible result types of the different parameters operations. - enum class ParameterResultType - { - Success, - AlreadyDeclared, - InvalidType, - NotDeclared, - ClientTimeout, - Unexpected, - }; + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - /// \brief The return type used in all falible parameters methods. - class ParameterResult { - /// \brief Construct. - /// \param _resultType Type of result of the operation. - public: GZ_TRANSPORT_PARAMETERS_VISIBLE - explicit ParameterResult(ParameterResultType _resultType); + /// \brief Possible result types of the different parameters operations. + enum class ParameterResultType + { + Success, + AlreadyDeclared, + InvalidType, + NotDeclared, + ClientTimeout, + Unexpected, + }; - /// \brief Construct. - /// \param _resultType Type of result of the operation. - /// \param _paramName Name of the related parameter. - public: GZ_TRANSPORT_PARAMETERS_VISIBLE - ParameterResult( - ParameterResultType _resultType, const std::string & _paramName); + /// \brief The return type used in all falible parameters methods. + class ParameterResult { + /// \brief Construct. + /// \param _resultType Type of result of the operation. + public: GZ_TRANSPORT_PARAMETERS_VISIBLE + explicit ParameterResult(ParameterResultType _resultType); - /// \brief Construct. - /// \param _resultType Type of result of the operation. - /// \param _paramName Name of the related parameter. - /// \param _paramType Type of the related parameter. - public: GZ_TRANSPORT_PARAMETERS_VISIBLE - ParameterResult( - ParameterResultType _resultType, - const std::string & _paramName, - const std::string & _paramType); + /// \brief Construct. + /// \param _resultType Type of result of the operation. + /// \param _paramName Name of the related parameter. + public: GZ_TRANSPORT_PARAMETERS_VISIBLE + ParameterResult( + ParameterResultType _resultType, const std::string & _paramName); - /// \brief Return the result type. - public: GZ_TRANSPORT_PARAMETERS_VISIBLE - ParameterResultType ResultType() const; + /// \brief Construct. + /// \param _resultType Type of result of the operation. + /// \param _paramName Name of the related parameter. + /// \param _paramType Type of the related parameter. + public: GZ_TRANSPORT_PARAMETERS_VISIBLE + ParameterResult( + ParameterResultType _resultType, + const std::string & _paramName, + const std::string & _paramType); - /// \brief Return the related parameter name. - public: GZ_TRANSPORT_PARAMETERS_VISIBLE - const std::string & ParamName() const; + /// \brief Return the result type. + public: GZ_TRANSPORT_PARAMETERS_VISIBLE + ParameterResultType ResultType() const; - /// \brief Return the related parameter type. - public: GZ_TRANSPORT_PARAMETERS_VISIBLE - const std::string & ParamType() const; + /// \brief Return the related parameter name. + public: GZ_TRANSPORT_PARAMETERS_VISIBLE + const std::string & ParamName() const; - /// \brief Coercion to bool type. - /// True if ParameterErrorType::Success, else False. - public: GZ_TRANSPORT_PARAMETERS_VISIBLE - explicit operator bool() const; + /// \brief Return the related parameter type. + public: GZ_TRANSPORT_PARAMETERS_VISIBLE + const std::string & ParamType() const; - private: ParameterResultType resultType; - private: std::string paramName; - private: std::string paramType; - }; + /// \brief Coercion to bool type. + /// True if ParameterErrorType::Success, else False. + public: GZ_TRANSPORT_PARAMETERS_VISIBLE + explicit operator bool() const; - /// \brief Stream operator, for debug output. - GZ_TRANSPORT_PARAMETERS_VISIBLE - std::ostream & operator<<(std::ostream &, const ParameterResult &); - } - } - } -} + private: ParameterResultType resultType; + private: std::string paramName; + private: std::string paramType; + }; -#endif + /// \brief Stream operator, for debug output. + GZ_TRANSPORT_PARAMETERS_VISIBLE + std::ostream & operator<<(std::ostream &, const ParameterResult &); + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::parameters +#endif // GZ_TRANSPORT_PARAMETERS_EXCEPTIONS_HH_ diff --git a/parameters/src/Client.cc b/parameters/src/Client.cc index 02aaeb219..98283e51b 100644 --- a/parameters/src/Client.cc +++ b/parameters/src/Client.cc @@ -31,11 +31,11 @@ #include "Utils.hh" -using namespace gz; -using namespace transport; -using namespace parameters; - -struct transport::parameters::ParametersClientPrivate +namespace gz::transport::parameters +{ +// Inline bracket to help doxygen filtering. +inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { +struct ParametersClientPrivate { ParametersClientPrivate( const std::string & _serverNamespace, @@ -47,6 +47,7 @@ struct transport::parameters::ParametersClientPrivate mutable transport::Node node; unsigned int timeoutMs; }; +} // namespace GZ_TRANSPORT_VERSION_NAMESPACE ////////////////////////////////////////////////// ParametersClient::~ParametersClient() = default; @@ -243,3 +244,4 @@ ParametersClient::ListParameters() const } return res; } +} // namespace gz::transport::parameters diff --git a/parameters/src/Registry.cc b/parameters/src/Registry.cc index 0e6d308b3..d23ad64f4 100644 --- a/parameters/src/Registry.cc +++ b/parameters/src/Registry.cc @@ -38,11 +38,11 @@ #include "Utils.hh" -using namespace gz; -using namespace transport; -using namespace parameters; - -struct transport::parameters::ParametersRegistryPrivate +namespace gz::transport::parameters +{ +// Inline bracket to help doxygen filtering. +inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { +struct ParametersRegistryPrivate { using ParametersMapT = std::unordered_map< std::string, std::unique_ptr>; @@ -78,6 +78,7 @@ struct transport::parameters::ParametersRegistryPrivate std::mutex parametersMapMutex; ParametersMapT parametersMap; }; +} // namespace GZ_TRANSPORT_VERSION_NAMESPACE ////////////////////////////////////////////////// ParametersRegistry::ParametersRegistry( @@ -359,3 +360,4 @@ ParametersRegistry::ListParameters() const dataPtr->ListParameters(unused, ret); return ret; } +} // namespace gz::transport::parameters diff --git a/parameters/src/Utils.cc b/parameters/src/Utils.cc index 32feae74d..a18f2cdf2 100644 --- a/parameters/src/Utils.cc +++ b/parameters/src/Utils.cc @@ -20,11 +20,13 @@ #include #include #include -using namespace gz; + +namespace gz::transport::parameters +{ +// Inline bracket to help doxygen filtering. +inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { ////////////////////////////////////////////////// -std::string -transport::parameters::addGzMsgsPrefix( - const std::string &_gzType) +std::string addGzMsgsPrefix(const std::string &_gzType) { std::ostringstream oss{"gz_msgs.", std::ios_base::ate}; oss << _gzType; @@ -32,8 +34,7 @@ transport::parameters::addGzMsgsPrefix( } ////////////////////////////////////////////////// -std::optional -transport::parameters::getGzTypeFromAnyProto( +std::optional getGzTypeFromAnyProto( const google::protobuf::Any &_any) { auto typeUrl = _any.type_url(); @@ -48,3 +49,5 @@ transport::parameters::getGzTypeFromAnyProto( } return ret.substr(sizeof(prefix) - 1); } +} // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::parameters diff --git a/parameters/src/Utils.hh b/parameters/src/Utils.hh index de20db18b..70ae6577a 100644 --- a/parameters/src/Utils.hh +++ b/parameters/src/Utils.hh @@ -33,31 +33,24 @@ #pragma warning(pop) #endif // defined(_MSC_VER) -namespace gz +namespace gz::transport::parameters { - namespace transport - { - namespace parameters - { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - - /// \brief Return the protobuf type prefixed with "gz_msgs." - /// \param[in] _gzType Type name to be prefixed. - /// \return The protobuf type with the prefix added. - GZ_TRANSPORT_PARAMETERS_VISIBLE - std::string addGzMsgsPrefix(const std::string &_gzType); - - /// \brief Get the gz message type from a protobuf message. - /// \param[in] _any Message to get the type. - /// \return A string with the gazebo protobuf type, - /// or nullopt if it fails. - GZ_TRANSPORT_PARAMETERS_VISIBLE - std::optional getGzTypeFromAnyProto( - const google::protobuf::Any &_any); - } - } - } -} - -#endif + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + + /// \brief Return the protobuf type prefixed with "gz_msgs." + /// \param[in] _gzType Type name to be prefixed. + /// \return The protobuf type with the prefix added. + GZ_TRANSPORT_PARAMETERS_VISIBLE + std::string addGzMsgsPrefix(const std::string &_gzType); + + /// \brief Get the gz message type from a protobuf message. + /// \param[in] _any Message to get the type. + /// \return A string with the gazebo protobuf type, + /// or nullopt if it fails. + GZ_TRANSPORT_PARAMETERS_VISIBLE + std::optional getGzTypeFromAnyProto( + const google::protobuf::Any &_any); + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::parameters +#endif // GZ_TRANSPORT_PARAMETERS_UTILS_HH_ diff --git a/parameters/src/result.cc b/parameters/src/result.cc index 3e27d68e0..f575d0706 100644 --- a/parameters/src/result.cc +++ b/parameters/src/result.cc @@ -20,10 +20,10 @@ #include "gz/transport/parameters/result.hh" -using namespace gz; -using namespace transport; -using namespace parameters; - +namespace gz::transport::parameters +{ +// Inline bracket to help doxygen filtering. +inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { ////////////////////////////////////////////////// ParameterResult::ParameterResult(ParameterResultType _resultType) : resultType{_resultType} @@ -70,8 +70,7 @@ ParameterResult::operator bool() const } ////////////////////////////////////////////////// -std::ostream & -transport::parameters::operator<<( +std::ostream & operator<<( std::ostream & os, const ParameterResult & ret) { std::ostringstream ss; @@ -105,3 +104,5 @@ transport::parameters::operator<<( os << ss.str(); return os; } +} // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport::parameters diff --git a/src/AdvertiseOptions.cc b/src/AdvertiseOptions.cc index 17537b7d5..6f6e2630c 100644 --- a/src/AdvertiseOptions.cc +++ b/src/AdvertiseOptions.cc @@ -22,56 +22,48 @@ #include "gz/transport/AdvertiseOptions.hh" #include "gz/transport/Helpers.hh" -using namespace gz; -using namespace transport; - -namespace gz -{ - namespace transport - { - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE - { - /// \internal - /// \brief Private data for AdvertiseOptions class. - class AdvertiseOptionsPrivate - { - /// \brief Constructor. - public: AdvertiseOptionsPrivate() = default; - - /// \brief Destructor. - public: virtual ~AdvertiseOptionsPrivate() = default; - - /// \brief Default scope value. - public: Scope_t scope = Scope_t::ALL; - }; - - /// \internal - /// \brief Private data for AdvertiseMessageOptions class. - class AdvertiseMessageOptionsPrivate - { - /// \brief Constructor. - public: AdvertiseMessageOptionsPrivate() = default; - - /// \brief Destructor. - public: virtual ~AdvertiseMessageOptionsPrivate() = default; - - /// \brief Default message publication rate. - public: uint64_t msgsPerSec = kUnthrottled; - }; - - /// \internal - /// \brief Private data for AdvertiseServiceOptions class. - class AdvertiseServiceOptionsPrivate - { - /// \brief Constructor. - public: AdvertiseServiceOptionsPrivate() = default; - - /// \brief Destructor. - public: virtual ~AdvertiseServiceOptionsPrivate() = default; - }; - } - } -} +namespace gz::transport +{ +inline namespace GZ_TRANSPORT_VERSION_NAMESPACE +{ +/// \internal +/// \brief Private data for AdvertiseOptions class. +class AdvertiseOptionsPrivate +{ + /// \brief Constructor. + public: AdvertiseOptionsPrivate() = default; + + /// \brief Destructor. + public: virtual ~AdvertiseOptionsPrivate() = default; + + /// \brief Default scope value. + public: Scope_t scope = Scope_t::ALL; +}; + +/// \internal +/// \brief Private data for AdvertiseMessageOptions class. +class AdvertiseMessageOptionsPrivate +{ + /// \brief Constructor. + public: AdvertiseMessageOptionsPrivate() = default; + + /// \brief Destructor. + public: virtual ~AdvertiseMessageOptionsPrivate() = default; + + /// \brief Default message publication rate. + public: uint64_t msgsPerSec = kUnthrottled; +}; + +/// \internal +/// \brief Private data for AdvertiseServiceOptions class. +class AdvertiseServiceOptionsPrivate +{ + /// \brief Constructor. + public: AdvertiseServiceOptionsPrivate() = default; + + /// \brief Destructor. + public: virtual ~AdvertiseServiceOptionsPrivate() = default; +}; ////////////////////////////////////////////////// AdvertiseOptions::AdvertiseOptions() @@ -225,3 +217,5 @@ bool AdvertiseServiceOptions::operator!=( { return !(*this == _other); } +} // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport diff --git a/src/Clock.cc b/src/Clock.cc index c7a317b37..3a7a1fd09 100644 --- a/src/Clock.cc +++ b/src/Clock.cc @@ -25,10 +25,12 @@ #include #include -using namespace gz::transport; - +namespace gz::transport +{ +inline namespace GZ_TRANSPORT_VERSION_NAMESPACE +{ ////////////////////////////////////////////////// -class gz::transport::NetworkClock::Implementation +class NetworkClock::Implementation { /// \brief Implementation constructor. /// \param[in] _topicName Name of the gz::msgs::Clock type @@ -272,3 +274,5 @@ bool WallClock::IsReady() const { return true; // Always ready. } +} // GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport diff --git a/src/Discovery.cc b/src/Discovery.cc index 5aa0cea73..3f7943d8b 100644 --- a/src/Discovery.cc +++ b/src/Discovery.cc @@ -38,9 +38,7 @@ #endif #endif -namespace gz -{ -namespace transport +namespace gz::transport { inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { @@ -65,6 +63,5 @@ inline namespace GZ_TRANSPORT_VERSION_NAMESPACE // Return if we got a reply. return items[0].revents & ZMQ_POLLIN; } -} -} -} +} // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport diff --git a/src/Helpers.cc b/src/Helpers.cc index 5e4ebf496..601bf0ec8 100644 --- a/src/Helpers.cc +++ b/src/Helpers.cc @@ -26,55 +26,52 @@ #include "gz/transport/Helpers.hh" -namespace gz +namespace gz::transport { - namespace transport + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE - { - ////////////////////////////////////////////////// - bool env(const std::string &_name, std::string &_value) - { - char *v; + ////////////////////////////////////////////////// + bool env(const std::string &_name, std::string &_value) + { + char *v; #ifdef _MSC_VER - size_t sz = 0; - _dupenv_s(&v, &sz, _name.c_str()); + size_t sz = 0; + _dupenv_s(&v, &sz, _name.c_str()); #else - v = std::getenv(_name.c_str()); + v = std::getenv(_name.c_str()); #endif - if (v) - { - _value = v; - return true; - } - return false; + if (v) + { + _value = v; + return true; } + return false; + } - ////////////////////////////////////////////////// - std::vector split(const std::string &_orig, char _delim) + ////////////////////////////////////////////////// + std::vector split(const std::string &_orig, char _delim) + { + std::vector pieces; + size_t pos1 = 0; + size_t pos2 = _orig.find(_delim); + while (pos2 != std::string::npos) { - std::vector pieces; - size_t pos1 = 0; - size_t pos2 = _orig.find(_delim); - while (pos2 != std::string::npos) - { - pieces.push_back(_orig.substr(pos1, pos2-pos1)); - pos1 = pos2 + 1; - pos2 = _orig.find(_delim, pos2 + 1); - } - pieces.push_back(_orig.substr(pos1, _orig.size()-pos1)); - return pieces; + pieces.push_back(_orig.substr(pos1, pos2-pos1)); + pos1 = pos2 + 1; + pos2 = _orig.find(_delim, pos2 + 1); } + pieces.push_back(_orig.substr(pos1, _orig.size()-pos1)); + return pieces; + } - ////////////////////////////////////////////////// - unsigned int getProcessId() - { + ////////////////////////////////////////////////// + unsigned int getProcessId() + { #ifdef _WIN32 - return ::GetCurrentProcessId(); + return ::GetCurrentProcessId(); #else - return ::getpid(); + return ::getpid(); #endif - } - } } -} + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport diff --git a/src/MessageInfo.cc b/src/MessageInfo.cc index 78b30c3f1..44f3f4995 100644 --- a/src/MessageInfo.cc +++ b/src/MessageInfo.cc @@ -20,40 +20,32 @@ #include "gz/transport/MessageInfo.hh" #include "gz/transport/TopicUtils.hh" -using namespace gz; -using namespace transport; - -namespace gz -{ - namespace transport - { - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE - { - /// \internal - /// \brief Private data for MessageInfo class. - class MessageInfoPrivate - { - /// \brief Default constructor. - public: MessageInfoPrivate() = default; - - /// \brief Destructor. - public: virtual ~MessageInfoPrivate() = default; - - /// \brief Topic name. - public: std::string topic = ""; - - /// \brief Message type name. - public: std::string type = ""; - - /// \brief Partition name. - public: std::string partition = ""; - - /// \brief Was the message sent via intra-process? - public: bool isIntraProcess = false; - }; - } - } -} +namespace gz::transport +{ +inline namespace GZ_TRANSPORT_VERSION_NAMESPACE +{ +/// \internal +/// \brief Private data for MessageInfo class. +class MessageInfoPrivate +{ + /// \brief Default constructor. + public: MessageInfoPrivate() = default; + + /// \brief Destructor. + public: virtual ~MessageInfoPrivate() = default; + + /// \brief Topic name. + public: std::string topic = ""; + + /// \brief Message type name. + public: std::string type = ""; + + /// \brief Partition name. + public: std::string partition = ""; + + /// \brief Was the message sent via intra-process? + public: bool isIntraProcess = false; +}; ////////////////////////////////////////////////// MessageInfo::MessageInfo() @@ -135,3 +127,6 @@ void MessageInfo::SetIntraProcess(bool _value) { this->dataPtr->isIntraProcess = _value; } + +} // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport diff --git a/src/NetUtils.cc b/src/NetUtils.cc index e22228454..fc1f88a5b 100644 --- a/src/NetUtils.cc +++ b/src/NetUtils.cc @@ -47,11 +47,7 @@ # include #endif -using namespace gz; - -namespace gz -{ -namespace transport +namespace gz::transport { inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { @@ -59,7 +55,7 @@ inline namespace GZ_TRANSPORT_VERSION_NAMESPACE /// Note that we don't consider private IP addresses. /// \param[out] _ip The preferred local IP address. /// \return true if a public local IP was found or false otherwise. - static bool preferredPublicIP(std::string &_ip) + bool preferredPublicIP(std::string &_ip) { char host[1024]; memset(host, 0, sizeof(host)); @@ -403,6 +399,5 @@ inline namespace GZ_TRANSPORT_VERSION_NAMESPACE return result; #endif } -} -} -} +} // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport diff --git a/src/Node.cc b/src/Node.cc index 4dbc29598..6c9f6db3d 100644 --- a/src/Node.cc +++ b/src/Node.cc @@ -41,172 +41,164 @@ #include "NodePrivate.hh" #include "NodeSharedPrivate.hh" -using namespace gz; -using namespace transport; - -namespace gz +namespace gz::transport { - namespace transport - { - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE - { - /// \brief Flag to detect SIGINT or SIGTERM while the code is executing - /// waitForShutdown(). - static bool g_shutdown = false; +inline namespace GZ_TRANSPORT_VERSION_NAMESPACE +{ +/// \brief Flag to detect SIGINT or SIGTERM while the code is executing +/// waitForShutdown(). +static bool g_shutdown = false; - /// \brief Mutex to protect the boolean shutdown variable. - static std::mutex g_shutdown_mutex; +/// \brief Mutex to protect the boolean shutdown variable. +static std::mutex g_shutdown_mutex; - /// \brief Condition variable to wakeup waitForShutdown() and exit. - static std::condition_variable g_shutdown_cv; +/// \brief Condition variable to wakeup waitForShutdown() and exit. +static std::condition_variable g_shutdown_cv; - ////////////////////////////////////////////////// - /// \brief Function executed when a SIGINT or SIGTERM signals are captured. - /// \param[in] _signal Signal received. - static void signal_handler(const int _signal) - { - if (_signal == SIGINT || _signal == SIGTERM) - { - g_shutdown_mutex.lock(); - g_shutdown = true; - g_shutdown_mutex.unlock(); - g_shutdown_cv.notify_all(); - } - } +////////////////////////////////////////////////// +/// \brief Function executed when a SIGINT or SIGTERM signals are captured. +/// \param[in] _signal Signal received. +static void signal_handler(const int _signal) +{ + if (_signal == SIGINT || _signal == SIGTERM) + { + g_shutdown_mutex.lock(); + g_shutdown = true; + g_shutdown_mutex.unlock(); + g_shutdown_cv.notify_all(); + } +} - ////////////////////////////////////////////////// - int rcvHwm() - { - return NodeShared::Instance()->RcvHwm(); - } +////////////////////////////////////////////////// +int rcvHwm() +{ + return NodeShared::Instance()->RcvHwm(); +} - ////////////////////////////////////////////////// - int sndHwm() - { - return NodeShared::Instance()->SndHwm(); - } +////////////////////////////////////////////////// +int sndHwm() +{ + return NodeShared::Instance()->SndHwm(); +} - ////////////////////////////////////////////////// - void waitForShutdown() - { - // Install a signal handler for SIGINT and SIGTERM. - std::signal(SIGINT, signal_handler); - std::signal(SIGTERM, signal_handler); +////////////////////////////////////////////////// +void waitForShutdown() +{ + // Install a signal handler for SIGINT and SIGTERM. + std::signal(SIGINT, signal_handler); + std::signal(SIGTERM, signal_handler); - std::unique_lock lk(g_shutdown_mutex); - g_shutdown_cv.wait(lk, []{return g_shutdown;}); - } + std::unique_lock lk(g_shutdown_mutex); + g_shutdown_cv.wait(lk, []{return g_shutdown;}); +} - ////////////////////////////////////////////////// - /// \internal - /// \brief Private data for Node::Publisher class. - class Node::PublisherPrivate - { - /// \brief Default constructor. - public: PublisherPrivate() - : shared(NodeShared::Instance()) - { - } +////////////////////////////////////////////////// +/// \internal +/// \brief Private data for Node::Publisher class. +class Node::PublisherPrivate +{ + /// \brief Default constructor. + public: PublisherPrivate() + : shared(NodeShared::Instance()) + { + } - /// \brief Constructor - /// \param[in] _publisher The message publisher. - public: explicit PublisherPrivate(const MessagePublisher &_publisher) - : shared(NodeShared::Instance()), - publisher(_publisher) - { - } + /// \brief Constructor + /// \param[in] _publisher The message publisher. + public: explicit PublisherPrivate(const MessagePublisher &_publisher) + : shared(NodeShared::Instance()), + publisher(_publisher) + { + } - /// \brief Check if this Publisher is ready to send an update based on - /// publication settings and the clock. - /// - /// \return True if it is okay to publish, false otherwise. - public: bool ThrottledUpdateReady() const - { - if (!this->publisher.Options().Throttled()) - return true; + /// \brief Check if this Publisher is ready to send an update based on + /// publication settings and the clock. + /// + /// \return True if it is okay to publish, false otherwise. + public: bool ThrottledUpdateReady() const + { + if (!this->publisher.Options().Throttled()) + return true; - Timestamp now = std::chrono::steady_clock::now(); + Timestamp now = std::chrono::steady_clock::now(); - std::lock_guard lk(this->mutex); - auto elapsed = now - this->lastCbTimestamp; - return std::chrono::duration_cast( - elapsed).count() >= this->periodNs; - } + std::lock_guard lk(this->mutex); + auto elapsed = now - this->lastCbTimestamp; + return std::chrono::duration_cast( + elapsed).count() >= this->periodNs; + } - /// \brief Check if this Publisher is ready to send an update based on - /// publication settings and the clock. - /// - /// This additionally advances the internal timestamp by one period. - /// - /// \return True if it is okay to publish, false otherwise. - public: bool UpdateThrottling() - { - if (!this->publisher.Options().Throttled()) - return true; + /// \brief Check if this Publisher is ready to send an update based on + /// publication settings and the clock. + /// + /// This additionally advances the internal timestamp by one period. + /// + /// \return True if it is okay to publish, false otherwise. + public: bool UpdateThrottling() + { + if (!this->publisher.Options().Throttled()) + return true; - if (!this->ThrottledUpdateReady()) - return false; + if (!this->ThrottledUpdateReady()) + return false; - // Update the last callback execution. - std::lock_guard lk(this->mutex); - this->lastCbTimestamp = std::chrono::steady_clock::now(); - return true; - } + // Update the last callback execution. + std::lock_guard lk(this->mutex); + this->lastCbTimestamp = std::chrono::steady_clock::now(); + return true; + } - /// \brief Check if this Publisher is valid - /// \return True if we have a topic to publish to, otherwise false. - public: bool Valid() - { - return !this->publisher.Topic().empty(); - } + /// \brief Check if this Publisher is valid + /// \return True if we have a topic to publish to, otherwise false. + public: bool Valid() + { + return !this->publisher.Topic().empty(); + } - /// \brief Destructor. - public: virtual ~PublisherPrivate() - { - std::lock_guard lk(this->shared->mutex); - // Notify the discovery service to unregister and unadvertise my topic. - if (!this->shared->dataPtr->msgDiscovery->Unadvertise( - this->publisher.Topic(), this->publisher.NUuid())) - { - std::cerr << "~PublisherPrivate() Error unadvertising topic [" - << this->publisher.Topic() << "]" << std::endl; - } - } + /// \brief Destructor. + public: virtual ~PublisherPrivate() + { + std::lock_guard lk(this->shared->mutex); + // Notify the discovery service to unregister and unadvertise my topic. + if (!this->shared->dataPtr->msgDiscovery->Unadvertise( + this->publisher.Topic(), this->publisher.NUuid())) + { + std::cerr << "~PublisherPrivate() Error unadvertising topic [" + << this->publisher.Topic() << "]" << std::endl; + } + } - /// \brief Create a MessageInfo object for this Publisher - MessageInfo CreateMessageInfo() - { - MessageInfo info; + /// \brief Create a MessageInfo object for this Publisher + MessageInfo CreateMessageInfo() + { + MessageInfo info; - // Set the topic and the partition at the same time - info.SetTopicAndPartition(this->publisher.Topic()); + // Set the topic and the partition at the same time + info.SetTopicAndPartition(this->publisher.Topic()); - // Set the message type name - info.SetType(this->publisher.MsgTypeName()); + // Set the message type name + info.SetType(this->publisher.MsgTypeName()); - return info; - } + return info; + } - /// \brief Pointer to the object shared between all the nodes within the - /// same process. - public: NodeShared *shared = nullptr; + /// \brief Pointer to the object shared between all the nodes within the + /// same process. + public: NodeShared *shared = nullptr; - /// \brief The message publisher. - public: MessagePublisher publisher; + /// \brief The message publisher. + public: MessagePublisher publisher; - /// \brief Timestamp of the last callback executed. - public: Timestamp lastCbTimestamp; + /// \brief Timestamp of the last callback executed. + public: Timestamp lastCbTimestamp; - /// \brief If throttling is enabled, the minimum period for receiving a - /// message in nanoseconds. - public: double periodNs = 0.0; + /// \brief If throttling is enabled, the minimum period for receiving a + /// message in nanoseconds. + public: double periodNs = 0.0; - /// \brief Mutex to protect the node::publisher from race conditions. - public: mutable std::mutex mutex; - }; - } - } -} + /// \brief Mutex to protect the node::publisher from race conditions. + public: mutable std::mutex mutex; +}; ////////////////////////////////////////////////// Node::Publisher::Publisher() @@ -1139,3 +1131,5 @@ bool Node::RequestRaw(const std::string &_topic, bool executed = this->Request(_topic, *req, _timeout, *res, _result); return executed && res->SerializeToString(&_response); } +} // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport diff --git a/src/NodeOptions.cc b/src/NodeOptions.cc index 86a9437c0..2c3047aa8 100644 --- a/src/NodeOptions.cc +++ b/src/NodeOptions.cc @@ -24,9 +24,8 @@ #include "NodeOptionsPrivate.hh" -using namespace gz; -using namespace transport; - +namespace gz::transport +{ ////////////////////////////////////////////////// NodeOptions::NodeOptions() : dataPtr(new NodeOptionsPrivate()) @@ -136,3 +135,4 @@ bool NodeOptions::TopicRemap(const std::string &_fromTopic, return topicIt != this->dataPtr->topicsRemap.end(); } +} // namespace gz::transport diff --git a/src/NodeOptionsPrivate.hh b/src/NodeOptionsPrivate.hh index 684557bf7..690f5b62b 100644 --- a/src/NodeOptionsPrivate.hh +++ b/src/NodeOptionsPrivate.hh @@ -24,34 +24,31 @@ #include "gz/transport/config.hh" #include "gz/transport/NetUtils.hh" -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \internal + /// \brief Private data for NodeOption class. + class NodeOptionsPrivate { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \internal - /// \brief Private data for NodeOption class. - class NodeOptionsPrivate - { - /// \brief Constructor. - public: NodeOptionsPrivate() = default; - - /// \brief Destructor. - public: virtual ~NodeOptionsPrivate() = default; - - /// \brief Namespace for this node. - public: std::string ns = ""; - - /// \brief Partition for this node. - public: std::string partition = hostname() + ":" + username(); - - /// \brief Table of remappings. The key is the original topic name and - /// its value is the new topic name to be used instead. - public: std::map topicsRemap; - }; - } - } -} -#endif + /// \brief Constructor. + public: NodeOptionsPrivate() = default; + + /// \brief Destructor. + public: virtual ~NodeOptionsPrivate() = default; + + /// \brief Namespace for this node. + public: std::string ns = ""; + + /// \brief Partition for this node. + public: std::string partition = hostname() + ":" + username(); + + /// \brief Table of remappings. The key is the original topic name and + /// its value is the new topic name to be used instead. + public: std::map topicsRemap; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_NODEOPTIONSPRIVATE_HH_ diff --git a/src/NodePrivate.hh b/src/NodePrivate.hh index 181140552..2a54b0702 100644 --- a/src/NodePrivate.hh +++ b/src/NodePrivate.hh @@ -26,62 +26,59 @@ #include "gz/transport/Node.hh" #include "gz/transport/NodeShared.hh" -namespace gz +namespace gz::transport { - namespace transport + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE - { - class NodeShared; - - /// \internal - /// \brief Private data for Node class. - class NodePrivate - { - /// \brief Constructor. - public: NodePrivate() = default; - - /// \brief Destructor. - public: virtual ~NodePrivate() = default; - - /// \brief Helper function for Subscribe. - /// \param[in] _fullyQualifiedTopic Fully qualified topic name - /// \return True on success. - /// \sa TopicUtils::FullyQualifiedName - public: bool SubscribeHelper(const std::string &_fullyQualifiedTopic); - - /// \brief Helper function to remove handlers from the shared publish - /// queue. This is called when the node unsubscribes to a topic - /// \param[in] _topic Topic that the node unsubcribed to. - /// \return True on success. - public: bool RemoveHandlersFromPubQueue(const std::string &_topic); - - /// \brief The list of topics subscribed by this node. - public: std::unordered_set topicsSubscribed; - - /// \brief The list of service calls advertised by this node. - public: std::unordered_set srvsAdvertised; - - /// \brief Node UUID. This ID is unique for each node. - public: std::string nUuid; - - /// \brief Pointer to the object shared between all the nodes within the - /// same process. - public: NodeShared *shared = NodeShared::Instance(); - - /// \brief Partition for this node. - public: std::string partition = hostname() + ":" + username(); - - /// \brief Default namespace for this node. - public: std::string ns = ""; - - /// \brief Custom options for this node. - public: NodeOptions options; - - /// \brief Statistics publisher. - public: Node::Publisher statPub; - }; - } - } -} -#endif + class NodeShared; + + /// \internal + /// \brief Private data for Node class. + class NodePrivate + { + /// \brief Constructor. + public: NodePrivate() = default; + + /// \brief Destructor. + public: virtual ~NodePrivate() = default; + + /// \brief Helper function for Subscribe. + /// \param[in] _fullyQualifiedTopic Fully qualified topic name + /// \return True on success. + /// \sa TopicUtils::FullyQualifiedName + public: bool SubscribeHelper(const std::string &_fullyQualifiedTopic); + + /// \brief Helper function to remove handlers from the shared publish + /// queue. This is called when the node unsubscribes to a topic + /// \param[in] _topic Topic that the node unsubcribed to. + /// \return True on success. + public: bool RemoveHandlersFromPubQueue(const std::string &_topic); + + /// \brief The list of topics subscribed by this node. + public: std::unordered_set topicsSubscribed; + + /// \brief The list of service calls advertised by this node. + public: std::unordered_set srvsAdvertised; + + /// \brief Node UUID. This ID is unique for each node. + public: std::string nUuid; + + /// \brief Pointer to the object shared between all the nodes within the + /// same process. + public: NodeShared *shared = NodeShared::Instance(); + + /// \brief Partition for this node. + public: std::string partition = hostname() + ":" + username(); + + /// \brief Default namespace for this node. + public: std::string ns = ""; + + /// \brief Custom options for this node. + public: NodeOptions options; + + /// \brief Statistics publisher. + public: Node::Publisher statPub; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_NODEPRIVATE_HH_ diff --git a/src/NodeShared.cc b/src/NodeShared.cc index ce9e8a0c8..e115c2d37 100644 --- a/src/NodeShared.cc +++ b/src/NodeShared.cc @@ -42,8 +42,6 @@ #include "NodeSharedPrivate.hh" using namespace std::chrono_literals; -using namespace gz; -using namespace transport; const char kGzAuthDomain[] = "gz-auth"; @@ -151,6 +149,8 @@ void sendAuthErrorHelper(zmq::socket_t &_socket, const std::string &_err) #endif } +namespace gz::transport +{ ////////////////////////////////////////////////// NodeShared *NodeShared::Instance() { @@ -1941,3 +1941,4 @@ int NodeSharedPrivate::NonNegativeEnvVar(const std::string &_envVar, } return numVal; } +} // namespace gz::transport diff --git a/src/NodeSharedPrivate.hh b/src/NodeSharedPrivate.hh index ccb9ba9e2..da330b34d 100644 --- a/src/NodeSharedPrivate.hh +++ b/src/NodeSharedPrivate.hh @@ -30,177 +30,174 @@ #include "gz/transport/Discovery.hh" #include "gz/transport/Node.hh" -namespace gz +namespace gz::transport { - namespace transport + // Inline bracket to help doxygen filtering. + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { + // + /// \brief Metadata for a publication. This is sent as part of the ZMQ + /// message for topic statistics. + class PublicationMetadata { - // Inline bracket to help doxygen filtering. - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - // - /// \brief Metadata for a publication. This is sent as part of the ZMQ - /// message for topic statistics. - class PublicationMetadata - { - /// \brief Publication timestamp. - public: uint64_t stamp = 0; + /// \brief Publication timestamp. + public: uint64_t stamp = 0; - /// \brief Sequence number, used to detect dropped messages. - public: uint64_t seq = 0; - }; + /// \brief Sequence number, used to detect dropped messages. + public: uint64_t seq = 0; + }; - // - // Private data class for NodeShared. - class NodeSharedPrivate + // + // Private data class for NodeShared. + class NodeSharedPrivate + { + // Constructor + public: NodeSharedPrivate() : + context(new zmq::context_t(1)), + publisher(new zmq::socket_t(*context, ZMQ_PUB)), + subscriber(new zmq::socket_t(*context, ZMQ_SUB)), + requester(new zmq::socket_t(*context, ZMQ_ROUTER)), + responseReceiver(new zmq::socket_t(*context, ZMQ_ROUTER)), + replier(new zmq::socket_t(*context, ZMQ_ROUTER)) { - // Constructor - public: NodeSharedPrivate() : - context(new zmq::context_t(1)), - publisher(new zmq::socket_t(*context, ZMQ_PUB)), - subscriber(new zmq::socket_t(*context, ZMQ_SUB)), - requester(new zmq::socket_t(*context, ZMQ_ROUTER)), - responseReceiver(new zmq::socket_t(*context, ZMQ_ROUTER)), - replier(new zmq::socket_t(*context, ZMQ_ROUTER)) - { - } - - /// \brief Initialize security - public: void SecurityInit(); - - /// \brief Handle new secure connections - public: void SecurityOnNewConnection(); - - /// \brief Access control handler for plain security. - /// This function is designed to be run in a thread. - public: void AccessControlHandler(); - - /// \brief Get and validate a non-negative environment variable. - /// \param[in] _envVar The name of the environment variable to get. - /// \param[in] _defaultValue The default value returned in case the - /// environment variable is invalid (e.g.: invalid number, - /// negative number). - /// \return The value read from the environment variable or the default - /// value if the validation wasn't succeed. - public: int NonNegativeEnvVar(const std::string &_envVar, - int _defaultValue) const; - - ////////////////////////////////////////////////// - /////// Declare here the ZMQ Context /////// - ////////////////////////////////////////////////// - - /// \brief 0MQ context. Always declare this object before any ZMQ socket - /// to make sure that the context is destroyed after all sockets. - public: std::unique_ptr context; + } - ////////////////////////////////////////////////// - /////// Declare here all ZMQ sockets /////// - ////////////////////////////////////////////////// + /// \brief Initialize security + public: void SecurityInit(); - /// \brief ZMQ socket to send topic updates. - public: std::unique_ptr publisher; - - /// \brief ZMQ socket to receive topic updates. - public: std::unique_ptr subscriber; - - /// \brief ZMQ socket for sending service call requests. - public: std::unique_ptr requester; - - /// \brief ZMQ socket for receiving service call responses. - public: std::unique_ptr responseReceiver; - - /// \brief ZMQ socket to receive service call requests. - public: std::unique_ptr replier; - - /// \brief Thread the handle access control - public: std::thread accessControlThread; - - ////////////////////////////////////////////////// - /////// Declare here the discovery object /////// - ////////////////////////////////////////////////// - - /// \brief Discovery service (messages). - public: std::unique_ptr msgDiscovery; - - /// \brief Discovery service (services). - public: std::unique_ptr srvDiscovery; - - ////////////////////////////////////////////////// - /////// Other private member variables /////// - ////////////////////////////////////////////////// - - /// \brief When true, the reception thread will finish. - public: std::atomic exit = false; - - /// \brief Timeout used for receiving messages (ms.). - public: inline static const int Timeout = 250; - - //////////////////////////////////////////////////////////////// - /////// The following is for asynchronous publication of /////// - /////// messages to local subscribers. /////// - //////////////////////////////////////////////////////////////// - - /// \brief Encapsulates information needed to publish a message. An - /// instance of this class is pushed onto a publish queue, pubQueue, when - /// a message is published through Node::Publisher::Publish. - /// The pubThread processes the pubQueue in the - /// NodeSharedPrivate::PublishThread function. - /// - /// A producer-consumer mechanism is used to send messages so that - /// Node::Publisher::Publish function does not block while executing - /// local subscriber callbacks. - public: struct PublishMsgDetails - { - /// \brief All the local subscription handlers. - public: std::vector localHandlers; - - /// \brief All the raw handlers. - public: std::vector rawHandlers; - - /// \brief Buffer for the raw handlers. - public: std::unique_ptr sharedBuffer = nullptr; + /// \brief Handle new secure connections + public: void SecurityOnNewConnection(); - /// \brief Msg copy for the local handlers. - public: std::unique_ptr msgCopy = nullptr; + /// \brief Access control handler for plain security. + /// This function is designed to be run in a thread. + public: void AccessControlHandler(); - /// \brief Message size. - // cppcheck-suppress unusedStructMember - public: std::size_t msgSize = 0; + /// \brief Get and validate a non-negative environment variable. + /// \param[in] _envVar The name of the environment variable to get. + /// \param[in] _defaultValue The default value returned in case the + /// environment variable is invalid (e.g.: invalid number, + /// negative number). + /// \return The value read from the environment variable or the default + /// value if the validation wasn't succeed. + public: int NonNegativeEnvVar(const std::string &_envVar, + int _defaultValue) const; - /// \brief Information about the topic and type. - public: MessageInfo info; - }; + ////////////////////////////////////////////////// + /////// Declare here the ZMQ Context /////// + ////////////////////////////////////////////////// - /// \brief Publish thread used to process the pubQueue. - public: std::thread pubThread; + /// \brief 0MQ context. Always declare this object before any ZMQ socket + /// to make sure that the context is destroyed after all sockets. + public: std::unique_ptr context; - /// \brief Mutex to protect the pubThread and pubQueue. - public: std::mutex pubThreadMutex; + ////////////////////////////////////////////////// + /////// Declare here all ZMQ sockets /////// + ////////////////////////////////////////////////// - /// \brief List onto which new messages are pushed. The pubThread - /// will pop off the messages and send them to local subscribers. - public: std::list> pubQueue; + /// \brief ZMQ socket to send topic updates. + public: std::unique_ptr publisher; - /// \brief used to signal when new work is available - public: std::condition_variable signalNewPub; + /// \brief ZMQ socket to receive topic updates. + public: std::unique_ptr subscriber; - /// \brief Handles local publication of messages on the pubQueue. - public: void PublishThread(); + /// \brief ZMQ socket for sending service call requests. + public: std::unique_ptr requester; - /// \brief Topic publication sequence numbers. - public: std::map topicPubSeq; + /// \brief ZMQ socket for receiving service call responses. + public: std::unique_ptr responseReceiver; - /// \brief True if topic statistics have been enabled. - public: bool topicStatsEnabled = false; + /// \brief ZMQ socket to receive service call requests. + public: std::unique_ptr replier; - /// \brief Statistics for a topic. The key in the map is the topic - /// name and the value contains the topic statistics. - public: std::map topicStats; + /// \brief Thread the handle access control + public: std::thread accessControlThread; - /// \brief Set of topics that have statistics enabled. - public: std::map> - enabledTopicStatistics; - }; - } - } -} -#endif + ////////////////////////////////////////////////// + /////// Declare here the discovery object /////// + ////////////////////////////////////////////////// + + /// \brief Discovery service (messages). + public: std::unique_ptr msgDiscovery; + + /// \brief Discovery service (services). + public: std::unique_ptr srvDiscovery; + + ////////////////////////////////////////////////// + /////// Other private member variables /////// + ////////////////////////////////////////////////// + + /// \brief When true, the reception thread will finish. + public: std::atomic exit = false; + + /// \brief Timeout used for receiving messages (ms.). + public: inline static const int Timeout = 250; + + //////////////////////////////////////////////////////////////// + /////// The following is for asynchronous publication of /////// + /////// messages to local subscribers. /////// + //////////////////////////////////////////////////////////////// + + /// \brief Encapsulates information needed to publish a message. An + /// instance of this class is pushed onto a publish queue, pubQueue, when + /// a message is published through Node::Publisher::Publish. + /// The pubThread processes the pubQueue in the + /// NodeSharedPrivate::PublishThread function. + /// + /// A producer-consumer mechanism is used to send messages so that + /// Node::Publisher::Publish function does not block while executing + /// local subscriber callbacks. + public: struct PublishMsgDetails + { + /// \brief All the local subscription handlers. + public: std::vector localHandlers; + + /// \brief All the raw handlers. + public: std::vector rawHandlers; + + /// \brief Buffer for the raw handlers. + public: std::unique_ptr sharedBuffer = nullptr; + + /// \brief Msg copy for the local handlers. + public: std::unique_ptr msgCopy = nullptr; + + /// \brief Message size. + // cppcheck-suppress unusedStructMember + public: std::size_t msgSize = 0; + + /// \brief Information about the topic and type. + public: MessageInfo info; + }; + + /// \brief Publish thread used to process the pubQueue. + public: std::thread pubThread; + + /// \brief Mutex to protect the pubThread and pubQueue. + public: std::mutex pubThreadMutex; + + /// \brief List onto which new messages are pushed. The pubThread + /// will pop off the messages and send them to local subscribers. + public: std::list> pubQueue; + + /// \brief used to signal when new work is available + public: std::condition_variable signalNewPub; + + /// \brief Handles local publication of messages on the pubQueue. + public: void PublishThread(); + + /// \brief Topic publication sequence numbers. + public: std::map topicPubSeq; + + /// \brief True if topic statistics have been enabled. + public: bool topicStatsEnabled = false; + + /// \brief Statistics for a topic. The key in the map is the topic + /// name and the value contains the topic statistics. + public: std::map topicStats; + + /// \brief Set of topics that have statistics enabled. + public: std::map> + enabledTopicStatistics; + }; + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_NODESHAREDPRIVATE_HH_ diff --git a/src/Publisher.cc b/src/Publisher.cc index 9292b2397..0cd06b39c 100644 --- a/src/Publisher.cc +++ b/src/Publisher.cc @@ -26,9 +26,8 @@ #include "gz/transport/NodeShared.hh" #include "gz/transport/SubscriptionHandler.hh" -using namespace gz; -using namespace transport; - +namespace gz::transport +{ ////////////////////////////////////////////////// Publisher::Publisher(const std::string &_topic, const std::string &_addr, const std::string &_pUuid, const std::string &_nUuid, @@ -354,3 +353,4 @@ bool ServicePublisher::operator!=(const ServicePublisher &_srv) const { return !(*this == _srv); } +} // namespace gz::transport diff --git a/src/SubscribeOptions.cc b/src/SubscribeOptions.cc index 6a0c1171b..73877a3b7 100644 --- a/src/SubscribeOptions.cc +++ b/src/SubscribeOptions.cc @@ -22,9 +22,8 @@ #include "SubscribeOptionsPrivate.hh" -using namespace gz; -using namespace transport; - +namespace gz::transport +{ ////////////////////////////////////////////////// SubscribeOptions::SubscribeOptions() : dataPtr(new SubscribeOptionsPrivate()) @@ -60,3 +59,4 @@ void SubscribeOptions::SetMsgsPerSec(const uint64_t _newMsgsPerSec) { this->dataPtr->msgsPerSec = _newMsgsPerSec; } +} // namespace gz::transport diff --git a/src/SubscribeOptionsPrivate.hh b/src/SubscribeOptionsPrivate.hh index 030ed63b8..619ebbd72 100644 --- a/src/SubscribeOptionsPrivate.hh +++ b/src/SubscribeOptionsPrivate.hh @@ -22,27 +22,24 @@ #include "gz/transport/Helpers.hh" -namespace gz +namespace gz::transport { - namespace transport + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE - { - /// \class SubscribeOptionsPrivate SubscribeOptionsPrivate.hh - /// gz/transport/SubscribeOptionsPrivate.hh - /// \brief Private data for the SubscribeOptions class. - class SubscribeOptionsPrivate - { - /// \brief Constructor. - public: SubscribeOptionsPrivate() = default; + /// \class SubscribeOptionsPrivate SubscribeOptionsPrivate.hh + /// gz/transport/SubscribeOptionsPrivate.hh + /// \brief Private data for the SubscribeOptions class. + class SubscribeOptionsPrivate + { + /// \brief Constructor. + public: SubscribeOptionsPrivate() = default; - /// \brief Destructor. - public: virtual ~SubscribeOptionsPrivate() = default; + /// \brief Destructor. + public: virtual ~SubscribeOptionsPrivate() = default; - /// \brief Default message subscription rate. - public: uint64_t msgsPerSec = kUnthrottled; - }; - } - } -} -#endif + /// \brief Default message subscription rate. + public: uint64_t msgsPerSec = kUnthrottled; + }; + } // GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport +#endif // GZ_TRANSPORT_SUBSCRIBEOPTIONSPRIVATE_HH_ diff --git a/src/SubscriptionHandler.cc b/src/SubscriptionHandler.cc index abefad85e..f5f5a1fbd 100644 --- a/src/SubscriptionHandler.cc +++ b/src/SubscriptionHandler.cc @@ -17,133 +17,130 @@ #include "gz/transport/SubscriptionHandler.hh" -namespace gz +namespace gz::transport { - namespace transport + inline namespace GZ_TRANSPORT_VERSION_NAMESPACE { - inline namespace GZ_TRANSPORT_VERSION_NAMESPACE - { - ///////////////////////////////////////////////// - SubscriptionHandlerBase::SubscriptionHandlerBase( - const std::string &_nUuid, - const SubscribeOptions &_opts) - : opts(_opts), - periodNs(0.0), - hUuid(Uuid().ToString()), - lastCbTimestamp(std::chrono::seconds{0}), - nUuid(_nUuid) - { - if (this->opts.Throttled()) - this->periodNs = 1e9 / this->opts.MsgsPerSec(); - } - - ///////////////////////////////////////////////// - std::string SubscriptionHandlerBase::NodeUuid() const - { - return this->nUuid; - } - - ///////////////////////////////////////////////// - std::string SubscriptionHandlerBase::HandlerUuid() const - { - return this->hUuid; - } + ///////////////////////////////////////////////// + SubscriptionHandlerBase::SubscriptionHandlerBase( + const std::string &_nUuid, + const SubscribeOptions &_opts) + : opts(_opts), + periodNs(0.0), + hUuid(Uuid().ToString()), + lastCbTimestamp(std::chrono::seconds{0}), + nUuid(_nUuid) + { + if (this->opts.Throttled()) + this->periodNs = 1e9 / this->opts.MsgsPerSec(); + } - ///////////////////////////////////////////////// - bool SubscriptionHandlerBase::UpdateThrottling() - { - if (!this->opts.Throttled()) - return true; + ///////////////////////////////////////////////// + std::string SubscriptionHandlerBase::NodeUuid() const + { + return this->nUuid; + } - Timestamp now = std::chrono::steady_clock::now(); + ///////////////////////////////////////////////// + std::string SubscriptionHandlerBase::HandlerUuid() const + { + return this->hUuid; + } - // Elapsed time since the last callback execution. - auto elapsed = now - this->lastCbTimestamp; + ///////////////////////////////////////////////// + bool SubscriptionHandlerBase::UpdateThrottling() + { + if (!this->opts.Throttled()) + return true; - if (std::chrono::duration_cast( - elapsed).count() < this->periodNs) - { - return false; - } + Timestamp now = std::chrono::steady_clock::now(); - // Update the last callback execution. - this->lastCbTimestamp = now; - return true; - } + // Elapsed time since the last callback execution. + auto elapsed = now - this->lastCbTimestamp; - ///////////////////////////////////////////////// - ISubscriptionHandler::ISubscriptionHandler( - const std::string &_nUuid, - const SubscribeOptions &_opts) - : SubscriptionHandlerBase(_nUuid, _opts) + if (std::chrono::duration_cast( + elapsed).count() < this->periodNs) { - // Do nothing + return false; } - ///////////////////////////////////////////////// - class RawSubscriptionHandler::Implementation - { - public: explicit Implementation(const std::string &_msgType) - : msgType(_msgType) - { - // Do nothing - } - - public: std::string msgType; - - public: RawCallback callback; - }; - - ///////////////////////////////////////////////// - RawSubscriptionHandler::RawSubscriptionHandler( - const std::string &_nUuid, - const std::string &_msgType, - const SubscribeOptions &_opts) - : SubscriptionHandlerBase(_nUuid, _opts), - pimpl(new Implementation(_msgType)) + // Update the last callback execution. + this->lastCbTimestamp = now; + return true; + } + + ///////////////////////////////////////////////// + ISubscriptionHandler::ISubscriptionHandler( + const std::string &_nUuid, + const SubscribeOptions &_opts) + : SubscriptionHandlerBase(_nUuid, _opts) + { + // Do nothing + } + + ///////////////////////////////////////////////// + class RawSubscriptionHandler::Implementation + { + public: explicit Implementation(const std::string &_msgType) + : msgType(_msgType) { // Do nothing } - ///////////////////////////////////////////////// - std::string RawSubscriptionHandler::TypeName() - { - return pimpl->msgType; - } + public: std::string msgType; + + public: RawCallback callback; + }; + + ///////////////////////////////////////////////// + RawSubscriptionHandler::RawSubscriptionHandler( + const std::string &_nUuid, + const std::string &_msgType, + const SubscribeOptions &_opts) + : SubscriptionHandlerBase(_nUuid, _opts), + pimpl(new Implementation(_msgType)) + { + // Do nothing + } + + ///////////////////////////////////////////////// + std::string RawSubscriptionHandler::TypeName() + { + return pimpl->msgType; + } - ///////////////////////////////////////////////// - void RawSubscriptionHandler::SetCallback(const RawCallback &_callback) + ///////////////////////////////////////////////// + void RawSubscriptionHandler::SetCallback(const RawCallback &_callback) + { + pimpl->callback = _callback; + } + + ///////////////////////////////////////////////// + bool RawSubscriptionHandler::RunRawCallback( + const char *_msgData, const size_t _size, + const MessageInfo &_info) + { + // Make sure we have a callback + if (!this->pimpl->callback) { - pimpl->callback = _callback; + std::cerr << "RawSubscriptionHandler::RunRawCallback() " + << "error: Callback is NULL" << std::endl; + return false; } - ///////////////////////////////////////////////// - bool RawSubscriptionHandler::RunRawCallback( - const char *_msgData, const size_t _size, - const MessageInfo &_info) - { - // Make sure we have a callback - if (!this->pimpl->callback) - { - std::cerr << "RawSubscriptionHandler::RunRawCallback() " - << "error: Callback is NULL" << std::endl; - return false; - } - - // Check if we need to throttle - if (!this->UpdateThrottling()) - return true; - - // Trigger the callback - this->pimpl->callback(_msgData, _size, _info); + // Check if we need to throttle + if (!this->UpdateThrottling()) return true; - } - ///////////////////////////////////////////////// - RawSubscriptionHandler::~RawSubscriptionHandler() - { - // Do nothing. This is here for pimpl. - } - } + // Trigger the callback + this->pimpl->callback(_msgData, _size, _info); + return true; + } + + ///////////////////////////////////////////////// + RawSubscriptionHandler::~RawSubscriptionHandler() + { + // Do nothing. This is here for pimpl. } -} + } // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport diff --git a/src/TopicStatistics.cc b/src/TopicStatistics.cc index a79b1aed8..477538836 100644 --- a/src/TopicStatistics.cc +++ b/src/TopicStatistics.cc @@ -22,10 +22,11 @@ #include "gz/transport/TopicStatistics.hh" -using namespace gz; -using namespace transport; - -class gz::transport::TopicStatisticsPrivate +namespace gz::transport +{ +inline namespace GZ_TRANSPORT_VERSION_NAMESPACE +{ +class TopicStatisticsPrivate { /// \brief Default constructor public: TopicStatisticsPrivate() = default; @@ -268,3 +269,5 @@ Statistics TopicStatistics::AgeStatistics() const { return this->dataPtr->age; } +} // namespace GZ_TRANSPORT_VERSION_NAMESPACE +} // namespace gz::transport diff --git a/src/TopicUtils.cc b/src/TopicUtils.cc index dea6e9bf3..11aa032c8 100644 --- a/src/TopicUtils.cc +++ b/src/TopicUtils.cc @@ -20,9 +20,8 @@ #include "gz/transport/TopicUtils.hh" -using namespace gz; -using namespace transport; - +namespace gz::transport +{ ////////////////////////////////////////////////// bool TopicUtils::IsValidNamespace(const std::string &_ns) { @@ -174,3 +173,4 @@ std::string TopicUtils::AsValidTopic(const std::string &_topic) return validTopic; } +} // namespace gz::transport diff --git a/src/Uuid.cc b/src/Uuid.cc index 782acade1..cb3dd56a5 100644 --- a/src/Uuid.cc +++ b/src/Uuid.cc @@ -20,8 +20,8 @@ #include "gz/transport/Uuid.hh" -using namespace gz; -using namespace transport; +namespace gz::transport +{ #ifdef _WIN32 /* Windows implementation using libuuid library */ @@ -86,5 +86,5 @@ std::string Uuid::ToString() const // Do not include the \0 in the string. return std::string(uuidStr.begin(), uuidStr.end() - 1); } - #endif +} // namespace gz::transport