Skip to content

Commit

Permalink
Add parameter to include hidden topics and services (ROS 2) (foxglove…
Browse files Browse the repository at this point in the history
…#216)

### Public-Facing Changes

- Add parameter to include hidden topics and services (not included by
default)

### Description
Adds the new parameter `include_hidden` which controls if hidden topics
or services are advertised.

From
https://design.ros2.org/articles/topic_and_service_names.html#hidden-topic-or-service-names:

> Any topic or service name that contains any tokens (either namespaces
or a topic or service name) that start with an underscore (_) will be
considered hidden and tools may not show them unless explicitly asked.
  • Loading branch information
achim-k committed Apr 14, 2023
1 parent daa0e01 commit a7736ce
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 1 deletion.
3 changes: 2 additions & 1 deletion README.md
Expand Up @@ -76,11 +76,12 @@ Parameters are provided to configure the behavior of the bridge. These parameter
* __client_topic_whitelist__: List of regular expressions ([ECMAScript grammar](https://en.cppreference.com/w/cpp/regex/ecmascript)) of whitelisted client-published topic names. Defaults to `[".*"]`.
* __send_buffer_limit__: Connection send buffer limit in bytes. Messages will be dropped when a connection's send buffer reaches this limit to avoid a queue of outdated messages building up. Defaults to `10000000` (10 MB).
* __use_compression__: Use websocket compression (permessage-deflate). Suited for connections with smaller bandwith, at the cost of additional CPU load.
* __capabilities__: List of supported [server capabilities](https://github.com/foxglove/ws-protocol/blob/main/docs/spec.md). Defaults to `[clientPublish,parameters,parametersSubscribe,services,connectionGraph]`.
* (ROS 1) __max_update_ms__: The maximum number of milliseconds to wait in between polling `roscore` for new topics, services, or parameters. Defaults to `5000`.
* (ROS 2) __num_threads__: The number of threads to use for the ROS node executor. This controls the number of subscriptions that can be processed in parallel. 0 means one thread per CPU core. Defaults to `0`.
* (ROS 2) __min_qos_depth__: Minimum depth used for the QoS profile of subscriptions. Defaults to `1`. This is to set a lower limit for a subscriber's QoS depth which is computed by summing up depths of all publishers. See also [#208](https://github.com/foxglove/ros-foxglove-bridge/issues/208).
* (ROS 2) __max_qos_depth__: Maximum depth used for the QoS profile of subscriptions. Defaults to `10`.
* (ROS 2) __capabilities__: List of supported [server capabilities](https://github.com/foxglove/ws-protocol/blob/main/docs/spec.md). Defaults to `[clientPublish,parameters,parametersSubscribe,services,connectionGraph]`.
* (ROS 2) __include_hidden__: Include hidden topics and services. Defaults to `false`.

## Building from source

Expand Down
Expand Up @@ -22,6 +22,7 @@ constexpr char PARAM_PARAMETER_WHITELIST[] = "param_whitelist";
constexpr char PARAM_USE_COMPRESSION[] = "use_compression";
constexpr char PARAM_CAPABILITIES[] = "capabilities";
constexpr char PARAM_CLIENT_TOPIC_WHITELIST[] = "client_topic_whitelist";
constexpr char PARAM_INCLUDE_HIDDEN[] = "include_hidden";

constexpr int64_t DEFAULT_PORT = 8765;
constexpr char DEFAULT_ADDRESS[] = "0.0.0.0";
Expand Down
2 changes: 2 additions & 0 deletions ros2_foxglove_bridge/launch/foxglove_bridge_launch.xml
Expand Up @@ -14,6 +14,7 @@
<arg name="send_buffer_limit" default="10000000" />
<arg name="use_sim_time" default="false" />
<arg name="capabilities" default="[clientPublish,parameters,parametersSubscribe,services,connectionGraph]" />
<arg name="include_hidden" default="false" />

<node pkg="foxglove_bridge" exec="foxglove_bridge">
<param name="port" value="$(var port)" />
Expand All @@ -31,5 +32,6 @@
<param name="send_buffer_limit" value="$(var send_buffer_limit)" />
<param name="use_sim_time" value="$(var use_sim_time)" />
<param name="capabilities" value="$(var capabilities)" />
<param name="include_hidden" value="$(var include_hidden)" />
</node>
</launch>
7 changes: 7 additions & 0 deletions ros2_foxglove_bridge/src/param_utils.cpp
Expand Up @@ -139,6 +139,13 @@ void declareParameters(rclcpp::Node* node) {
clientTopicWhiteListDescription.read_only = true;
node->declare_parameter(PARAM_CLIENT_TOPIC_WHITELIST, std::vector<std::string>({".*"}),
paramWhiteListDescription);

auto includeHiddenDescription = rcl_interfaces::msg::ParameterDescriptor{};
includeHiddenDescription.name = PARAM_INCLUDE_HIDDEN;
includeHiddenDescription.type = rcl_interfaces::msg::ParameterType::PARAMETER_BOOL;
includeHiddenDescription.description = "Include hidden topics and services";
includeHiddenDescription.read_only = true;
node->declare_parameter(PARAM_INCLUDE_HIDDEN, false, includeHiddenDescription);
}

std::vector<std::regex> parseRegexStrings(rclcpp::Node* node,
Expand Down
21 changes: 21 additions & 0 deletions ros2_foxglove_bridge/src/ros2_foxglove_bridge.cpp
Expand Up @@ -30,6 +30,15 @@ using ClientPublications = std::unordered_map<foxglove::ClientChannelId, Publica
using PublicationsByClient = std::map<ConnectionHandle, ClientPublications, std::owner_less<>>;
using foxglove::isWhitelisted;

namespace {
inline bool isHiddenTopicOrService(const std::string& name) {
if (name.empty()) {
throw std::invalid_argument("Topic or service name can't be empty");
}
return name.front() == '_' || name.find("/_") != std::string::npos;
}
} // namespace

namespace foxglove_bridge {

class FoxgloveBridge : public rclcpp::Node {
Expand Down Expand Up @@ -66,6 +75,7 @@ class FoxgloveBridge : public rclcpp::Node {
const auto clientTopicWhiteList =
this->get_parameter(PARAM_CLIENT_TOPIC_WHITELIST).as_string_array();
const auto clientTopicWhiteListPatterns = parseRegexStrings(this, clientTopicWhiteList);
_includeHidden = this->get_parameter(PARAM_INCLUDE_HIDDEN).as_bool();

const auto logHandler = std::bind(&FoxgloveBridge::logHandler, this, _1, _2);
foxglove::ServerOptions serverOptions;
Expand Down Expand Up @@ -193,6 +203,11 @@ class FoxgloveBridge : public rclcpp::Node {
const auto& topicName = topicNamesAndType.first;
const auto& datatypes = topicNamesAndType.second;

// Ignore hidden topics if not explicitly included
if (!_includeHidden && isHiddenTopicOrService(topicName)) {
continue;
}

// Ignore the topic if it is not on the topic whitelist
if (isWhitelisted(topicName, _topicWhitelistPatterns)) {
for (const auto& datatype : datatypes) {
Expand Down Expand Up @@ -326,6 +341,11 @@ class FoxgloveBridge : public rclcpp::Node {
continue;
}

// Ignore hidden services if not explicitly included
if (!_includeHidden && isHiddenTopicOrService(serviceName)) {
continue;
}

// Ignore the service if it is not on the service whitelist
if (!isWhitelisted(serviceName, _serviceWhitelistPatterns)) {
continue;
Expand Down Expand Up @@ -448,6 +468,7 @@ class FoxgloveBridge : public rclcpp::Node {
bool _useSimTime = false;
std::vector<std::string> _capabilities;
std::atomic<bool> _subscribeGraphUpdates = false;
bool _includeHidden = false;

void subscribeHandler(foxglove::ChannelId channelId, ConnectionHandle hdl) {
_handlerCallbackQueue->addCallback(std::bind(&FoxgloveBridge::subscribe, this, channelId, hdl));
Expand Down

0 comments on commit a7736ce

Please sign in to comment.