diff --git a/example/ros-graph-example.js b/example/ros-graph-example.js index ff02a9b3..ae8a3209 100644 --- a/example/ros-graph-example.js +++ b/example/ros-graph-example.js @@ -46,6 +46,11 @@ rclnodejs } ); + let clientNode = new rclnodejs.Node('client_node', 'ns2'); + clientNode.createClient( + 'example_interfaces/srv/AddTwoInts', + 'add_two_ints' + ); let node = rclnodejs.createNode('ros_graph_display_node', ns); let nodeNamesAndNameSpaces = node.getNodeNamesAndNamespaces(); @@ -118,6 +123,15 @@ rclnodejs ' ' ) ); + + console.log('CLIENTS BY NODE'); + console.log( + JSON.stringify( + node.getClientNamesAndTypesByNode('client_node', '/ns2'), + undefined, + ' ' + ) + ); }) .catch((e) => { console.log(`Error: ${e}`); diff --git a/lib/node.js b/lib/node.js index f132ba09..95d5ae0f 100644 --- a/lib/node.js +++ b/lib/node.js @@ -969,7 +969,7 @@ class Node extends rclnodejs.ShadowNode { } /** - * Get the list of service topics discovered by the provided node for the remote node name. + * Get service names and types for which a remote node has servers. * @param {string} nodeName - The name of the node. * @param {string} namespace - The name of the namespace. * @return {Array<{name: string, types: Array}>} - An array of the names and types. @@ -982,6 +982,20 @@ class Node extends rclnodejs.ShadowNode { ); } + /** + * Get service names and types for which a remote node has clients. + * @param {string} nodeName - The name of the node. + * @param {string} namespace - The name of the namespace. + * @return {Array<{name: string, types: Array}>} - An array of the names and types. + */ + getClientNamesAndTypesByNode(nodeName, namespace) { + return rclnodejs.getClientNamesAndTypesByNode( + this.handle, + nodeName, + namespace + ); + } + /** * Get the list of topics discovered by the provided node. * @param {boolean} noDemangle - If true topic names and types returned will not be demangled, default: false. diff --git a/src/rcl_bindings.cpp b/src/rcl_bindings.cpp index 4514d09e..7ee476ec 100644 --- a/src/rcl_bindings.cpp +++ b/src/rcl_bindings.cpp @@ -1738,15 +1738,45 @@ NAN_METHOD(GetServiceNamesAndTypesByNode) { rcl_get_service_names_and_types_by_node( node, &allocator, node_name.c_str(), node_namespace.c_str(), &service_names_and_types), - "Failed to get_publisher_names_and_types."); + "Failed to get_service_names_and_types."); v8::Local result_list = Nan::New(service_names_and_types.names.size); ExtractNamesAndTypes(service_names_and_types, &result_list); + THROW_ERROR_IF_NOT_EQUAL( + RCL_RET_OK, rcl_names_and_types_fini(&service_names_and_types), + "Failed to destroy rcl_get_zero_initialized_names_and_types"); + + info.GetReturnValue().Set(result_list); +} + +NAN_METHOD(GetClientNamesAndTypesByNode) { + v8::Local currentContent = Nan::GetCurrentContext(); + RclHandle* node_handle = RclHandle::Unwrap( + Nan::To(info[0]).ToLocalChecked()); + rcl_node_t* node = reinterpret_cast(node_handle->ptr()); + std::string node_name = + *Nan::Utf8String(info[1]->ToString(currentContent).ToLocalChecked()); + std::string node_namespace = + *Nan::Utf8String(info[2]->ToString(currentContent).ToLocalChecked()); + + rcl_names_and_types_t client_names_and_types = + rcl_get_zero_initialized_names_and_types(); + rcl_allocator_t allocator = rcl_get_default_allocator(); THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, - rcl_names_and_types_fini(&service_names_and_types), - "Failed to destroy topic_names_and_types"); + rcl_get_client_names_and_types_by_node( + node, &allocator, node_name.c_str(), + node_namespace.c_str(), &client_names_and_types), + "Failed to get_client_names_and_types."); + + v8::Local result_list = + Nan::New(client_names_and_types.names.size); + ExtractNamesAndTypes(client_names_and_types, &result_list); + + THROW_ERROR_IF_NOT_EQUAL( + RCL_RET_OK, rcl_names_and_types_fini(&client_names_and_types), + "Failed to destroy rcl_get_zero_initialized_names_and_types"); info.GetReturnValue().Set(result_list); } @@ -2033,6 +2063,7 @@ std::vector binding_methods = { {"getPublisherNamesAndTypesByNode", GetPublisherNamesAndTypesByNode}, {"getSubscriptionNamesAndTypesByNode", GetSubscriptionNamesAndTypesByNode}, {"getServiceNamesAndTypesByNode", GetServiceNamesAndTypesByNode}, + {"getClientNamesAndTypesByNode", GetClientNamesAndTypesByNode}, {"getTopicNamesAndTypes", GetTopicNamesAndTypes}, {"getServiceNamesAndTypes", GetServiceNamesAndTypes}, {"getNodeNames", GetNodeNames}, diff --git a/test/types/index.test-d.ts b/test/types/index.test-d.ts index 7597ccd8..fe4cdff8 100644 --- a/test/types/index.test-d.ts +++ b/test/types/index.test-d.ts @@ -56,6 +56,9 @@ expectType( expectType( node.getServiceNamesAndTypesByNode(NODE_NAME) ); +expectType( + node.getClientNamesAndTypesByNode(NODE_NAME) +); expectType( node.getSubscriptionNamesAndTypesByNode(NODE_NAME) ); diff --git a/types/node.d.ts b/types/node.d.ts index b6551629..038e62ae 100644 --- a/types/node.d.ts +++ b/types/node.d.ts @@ -685,6 +685,22 @@ declare module 'rclnodejs' { namespace?: string ): Array; + /** + * Get a remote node's client topics. + * + * @param remoteNodeName - Name of the remote node. + * @param namespace - Name of the remote namespace. + * @returns An array of the names and types. + * [ + * { name: '/rosout', types: [ 'rcl_interfaces/msg/Log' ] }, + * ... + * ] + */ + getClientNamesAndTypesByNode( + remoteNodeName: string, + namespace?: string + ): Array; + /** * Get this node's topics and corresponding types. *