Skip to content

Commit 3a0c105

Browse files
committed
add topic name remapping
Signed-off-by: Miaofei <[email protected]>
1 parent 1723927 commit 3a0c105

File tree

2 files changed

+90
-12
lines changed

2 files changed

+90
-12
lines changed

rclpy/rclpy/node.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,9 +1689,15 @@ def _get_info_by_topic(
16891689
no_mangle: bool,
16901690
func: Callable[[object, str, bool], List[Dict]]
16911691
) -> List[TopicEndpointInfo]:
1692-
fq_topic_name = expand_topic_name(topic_name, self.get_name(), self.get_namespace())
1693-
validate_full_topic_name(fq_topic_name)
16941692
with self.handle as node_capsule:
1693+
if no_mangle:
1694+
fq_topic_name = topic_name
1695+
else:
1696+
fq_topic_name = expand_topic_name(
1697+
topic_name, self.get_name(), self.get_namespace())
1698+
validate_full_topic_name(fq_topic_name)
1699+
fq_topic_name = _rclpy.rclpy_remap_topic_name(node_capsule, fq_topic_name)
1700+
16951701
info_dicts = func(node_capsule, fq_topic_name, no_mangle)
16961702
infos = [TopicEndpointInfo(**x) for x in info_dicts]
16971703
return infos

rclpy/src/rclpy/_rclpy.c

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@
2020
#include <rcl/node.h>
2121
#include <rcl/publisher.h>
2222
#include <rcl/rcl.h>
23+
#include <rcl/remap.h>
2324
#include <rcl/time.h>
2425
#include <rcl/validate_topic_name.h>
25-
#include <rcl_yaml_param_parser/parser.h>
2626
#include <rcl_interfaces/msg/parameter_type__struct.h>
27+
#include <rcl_yaml_param_parser/parser.h>
2728
#include <rcutils/allocator.h>
2829
#include <rcutils/format_string.h>
2930
#include <rcutils/strdup.h>
@@ -917,19 +918,23 @@ _get_info_by_topic(
917918
rcl_ret_t fini_ret;
918919
if (RCL_RET_OK != ret) {
919920
if (RCL_RET_BAD_ALLOC == ret) {
920-
PyErr_Format(PyExc_MemoryError, "Failed to get information by topic for %s: %s",
921+
PyErr_Format(
922+
PyExc_MemoryError, "Failed to get information by topic for %s: %s",
921923
type, rcl_get_error_string().str);
922924
} else if (RCL_RET_UNSUPPORTED == ret) {
923-
PyErr_Format(PyExc_NotImplementedError, "Failed to get information by topic for %s: "
925+
PyErr_Format(
926+
PyExc_NotImplementedError, "Failed to get information by topic for %s: "
924927
"function not supported by RMW_IMPLEMENTATION", type);
925928
} else {
926-
PyErr_Format(RCLError, "Failed to get information by topic for %s: %s",
929+
PyErr_Format(
930+
RCLError, "Failed to get information by topic for %s: %s",
927931
type, rcl_get_error_string().str);
928932
}
929933
rcl_reset_error();
930934
fini_ret = rcl_topic_endpoint_info_array_fini(&info_array, &allocator);
931935
if (fini_ret != RCL_RET_OK) {
932-
PyErr_Format(RCLError, "rcl_topic_endpoint_info_array_fini failed: %s",
936+
PyErr_Format(
937+
RCLError, "rcl_topic_endpoint_info_array_fini failed: %s",
933938
rcl_get_error_string().str);
934939
rcl_reset_error();
935940
}
@@ -1327,7 +1332,7 @@ _expand_topic_name_with_exceptions(const char * topic, const char * node, const
13271332
* \param[in] topic_name topic string to be expanded
13281333
* \param[in] node_name name of the node to be used during expansion
13291334
* \param[in] node_namespace namespace of the node to be used during expansion
1330-
* \return expanded node namespace
1335+
* \return expanded topic name
13311336
*/
13321337
static PyObject *
13331338
rclpy_expand_topic_name(PyObject * Py_UNUSED(self), PyObject * args)
@@ -1356,23 +1361,86 @@ rclpy_expand_topic_name(PyObject * Py_UNUSED(self), PyObject * args)
13561361
}
13571362

13581363
char * expanded_topic = _expand_topic_name_with_exceptions(topic, node_name, node_namespace);
1359-
13601364
if (!expanded_topic) {
13611365
// exception already set
13621366
return NULL;
13631367
}
13641368

13651369
PyObject * result = PyUnicode_FromString(expanded_topic);
1366-
if (!result) {
1367-
return NULL;
1368-
}
13691370

13701371
rcl_allocator_t allocator = rcl_get_default_allocator();
13711372
allocator.deallocate(expanded_topic, allocator.state);
13721373

13731374
return result;
13741375
}
13751376

1377+
static char *
1378+
_remap_topic_name_with_exceptions(const rcl_node_t * node_handle, const char * topic_name)
1379+
{
1380+
// Get the node options
1381+
const rcl_node_options_t * node_options = rcl_node_get_options(node_handle);
1382+
if (node_options == NULL) {
1383+
return NULL;
1384+
}
1385+
const rcl_arguments_t * global_args = NULL;
1386+
if (node_options->use_global_arguments) {
1387+
global_args = &(node_handle->context->global_arguments);
1388+
}
1389+
1390+
char * remapped_topic = NULL;
1391+
rcl_ret_t ret = rcl_remap_topic_name(
1392+
&(node_options->arguments),
1393+
global_args,
1394+
topic_name,
1395+
rcl_node_get_name(node_handle),
1396+
rcl_node_get_namespace(node_handle),
1397+
node_options->allocator,
1398+
&remapped_topic);
1399+
if (ret != RCL_RET_OK) {
1400+
PyErr_Format(PyExc_RuntimeError, "Failed to remap topic name %s", topic_name);
1401+
return NULL;
1402+
}
1403+
1404+
return remapped_topic;
1405+
}
1406+
1407+
/// Remap a topic name
1408+
/**
1409+
* Raises ValueError if the capsule is not the correct type
1410+
*
1411+
* \param[in] pynode Capsule pointing to the node
1412+
* \param[in] topic_name topic string to be remapped
1413+
* \return remapped topic name
1414+
*/
1415+
static PyObject *
1416+
rclpy_remap_topic_name(PyObject * Py_UNUSED(self), PyObject * args)
1417+
{
1418+
PyObject * pynode;
1419+
const char * topic_name;
1420+
1421+
if (!PyArg_ParseTuple(args, "Os", &pynode, &topic_name)) {
1422+
return NULL;
1423+
}
1424+
1425+
const rcl_node_t * node = (const rcl_node_t *)PyCapsule_GetPointer(pynode, "rcl_node_t");
1426+
if (node == NULL) {
1427+
return NULL;
1428+
}
1429+
1430+
char * remapped_topic_name = _remap_topic_name_with_exceptions(node, topic_name);
1431+
if (remapped_topic_name == NULL) {
1432+
return PyUnicode_FromString(topic_name);
1433+
}
1434+
1435+
PyObject * result = PyUnicode_FromString(remapped_topic_name);
1436+
1437+
const rcl_node_options_t * node_options = rcl_node_get_options(node_handle);
1438+
rcl_allocator_t allocator = node_options->allocator,
1439+
allocator.deallocate(remapped_topic_name, allocator.state);
1440+
1441+
return result;
1442+
}
1443+
13761444
/// PyCapsule destructor for publisher
13771445
static void
13781446
_rclpy_destroy_publisher(PyObject * pyentity)
@@ -4986,6 +5054,10 @@ static PyMethodDef rclpy_methods[] = {
49865054
"rclpy_expand_topic_name", rclpy_expand_topic_name, METH_VARARGS,
49875055
"Expand a topic name."
49885056
},
5057+
{
5058+
"rclpy_remap_topic_name", rclpy_remap_topic_name, METH_VARARGS,
5059+
"Remap a topic name."
5060+
},
49895061
{
49905062
"rclpy_get_validation_error_for_topic_name",
49915063
rclpy_get_validation_error_for_topic_name, METH_VARARGS,

0 commit comments

Comments
 (0)