Skip to content

Commit ba7cdc0

Browse files
authored
Support to resolve topic/service (#1175)
This pull request introduces support for resolving topic and service names with remapping and expansion functionality. Key changes include: - Addition of new tests in both TypeScript and JavaScript to verify the resolution behavior. - Implementation of a new C++ binding function (ResolveName) to expose the name resolution logic. - Updates to the Node class in JavaScript to provide resolveTopicName and resolveServiceName methods. Fix: #1174
1 parent af12346 commit ba7cdc0

File tree

5 files changed

+119
-0
lines changed

5 files changed

+119
-0
lines changed

lib/node.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,42 @@ class Node extends rclnodejs.ShadowNode {
16921692
return rclnodejs.getRMWImplementationIdentifier();
16931693
}
16941694

1695+
/**
1696+
* Return a topic name expanded and remapped.
1697+
* @param {string} topicName - Topic name to be expanded and remapped.
1698+
* @param {boolean} [onlyExpand=false] - If `true`, remapping rules won't be applied.
1699+
* @returns {string} - A fully qualified topic name.
1700+
*/
1701+
resolveTopicName(topicName, onlyExpand = false) {
1702+
if (typeof topicName !== 'string') {
1703+
throw new TypeError('Invalid argument: expected string');
1704+
}
1705+
return rclnodejs.resolveName(
1706+
this.handle,
1707+
topicName,
1708+
onlyExpand,
1709+
/*isService=*/ false
1710+
);
1711+
}
1712+
1713+
/**
1714+
* Return a service name expanded and remapped.
1715+
* @param {string} service - Service name to be expanded and remapped.
1716+
* @param {boolean} [onlyExpand=false] - If `true`, remapping rules won't be applied.
1717+
* @returns {string} - A fully qualified service name.
1718+
*/
1719+
resolveServiceName(service, onlyExpand = false) {
1720+
if (typeof service !== 'string') {
1721+
throw new TypeError('Invalid argument: expected string');
1722+
}
1723+
return rclnodejs.resolveName(
1724+
this.handle,
1725+
service,
1726+
onlyExpand,
1727+
/*isService=*/ true
1728+
);
1729+
}
1730+
16951731
// returns on 1st error or result {successful, reason}
16961732
_validateParameters(parameters = [], declareParameterMode = false) {
16971733
for (const parameter of parameters) {

src/rcl_node_bindings.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,37 @@ Napi::Value GetRMWImplementationIdentifier(const Napi::CallbackInfo& info) {
476476
return Napi::String::New(info.Env(), rmw_get_implementation_identifier());
477477
}
478478

479+
Napi::Value ResolveName(const Napi::CallbackInfo& info) {
480+
Napi::Env env = info.Env();
481+
482+
RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
483+
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
484+
const rcl_node_options_t* node_options = rcl_node_get_options(node);
485+
std::string topic_name = info[1].As<Napi::String>().Utf8Value();
486+
bool only_expand = info[2].As<Napi::Boolean>().Value();
487+
bool is_service = info[3].As<Napi::Boolean>().Value();
488+
489+
char* output_cstr = nullptr;
490+
rcl_ret_t ret =
491+
rcl_node_resolve_name(node, topic_name.c_str(), node_options->allocator,
492+
is_service, only_expand, &output_cstr);
493+
494+
auto name_deleter = [&]() {
495+
node_options->allocator.deallocate(output_cstr,
496+
node_options->allocator.state);
497+
};
498+
499+
RCPPUTILS_SCOPE_EXIT({ name_deleter(); });
500+
501+
if (RCL_RET_OK != ret) {
502+
Napi::Error::New(env, ("failed to resolve name"))
503+
.ThrowAsJavaScriptException();
504+
return env.Undefined();
505+
}
506+
507+
return Napi::String::New(env, output_cstr);
508+
}
509+
479510
Napi::Object InitNodeBindings(Napi::Env env, Napi::Object exports) {
480511
exports.Set("getParameterOverrides",
481512
Napi::Function::New(env, GetParameterOverrides));
@@ -500,6 +531,7 @@ Napi::Object InitNodeBindings(Napi::Env env, Napi::Object exports) {
500531
Napi::Function::New(env, GetFullyQualifiedName));
501532
exports.Set("getRMWImplementationIdentifier",
502533
Napi::Function::New(env, GetRMWImplementationIdentifier));
534+
exports.Set("resolveName", Napi::Function::New(env, ResolveName));
503535
return exports;
504536
}
505537

test/test-node.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,3 +654,36 @@ describe('Node arguments', function () {
654654
rclnodejs.shutdown();
655655
});
656656
});
657+
658+
describe('Test node resolve name', function () {
659+
let node = null;
660+
before(async function () {
661+
await rclnodejs.init();
662+
node = rclnodejs.createNode(
663+
'topic_resolver',
664+
'/my_ns',
665+
Context.defaultContext(),
666+
NodeOptions.defaultOptions,
667+
['--ros-args', '-r', 'foo:=bar']
668+
);
669+
});
670+
671+
after(function () {
672+
node.destroy();
673+
rclnodejs.shutdown();
674+
});
675+
676+
it('Resolve topic name', function (done) {
677+
assert.deepStrictEqual(node.resolveTopicName('foo'), '/my_ns/bar');
678+
assert.deepStrictEqual(node.resolveTopicName('/abs'), '/abs');
679+
assert.deepStrictEqual(node.resolveTopicName('foo', true), '/my_ns/foo');
680+
done();
681+
});
682+
683+
it('Resolve service name', function (done) {
684+
assert.deepStrictEqual(node.resolveServiceName('foo'), '/my_ns/bar');
685+
assert.deepStrictEqual(node.resolveServiceName('/abs'), '/abs');
686+
assert.deepStrictEqual(node.resolveServiceName('foo', true), '/my_ns/foo');
687+
done();
688+
});
689+
});

test/types/index.test-d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ const nodeWithArgs = rclnodejs.createNode(
9191
false
9292
);
9393
expectType<rclnodejs.Node>(nodeWithArgs);
94+
expectType<string>(node.resolveTopicName(TOPIC, true));
95+
expectType<string>(node.resolveServiceName(SERVICE_NAME, true));
9496

9597
// ---- LifecycleNode ----
9698
const lifecycleNode = rclnodejs.createLifecycleNode(LIFECYCLE_NODE_NAME);

types/node.d.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,5 +838,21 @@ declare module 'rclnodejs' {
838838
* @returns - The RMW implementation identifier.
839839
*/
840840
getRMWImplementationIdentifier(): string;
841+
842+
/**
843+
* Return a topic name expanded and remapped.
844+
* @param topicName - Topic name to be expanded and remapped.
845+
* @param onlyExpand - If `true`, remapping rules won't be applied, default is false.
846+
* @returns A fully qualified topic name.
847+
*/
848+
resolveTopicName(topicName: string, onlyExpand?: boolean): string;
849+
850+
/**
851+
* Return a service name expanded and remapped.
852+
* @param service - Service name to be expanded and remapped.
853+
* @param onlyExpand - If `true`, remapping rules won't be applied, default is false.
854+
* @returns A fully qualified service name.
855+
*/
856+
resolveServiceName(service: string, onlyExpand?: boolean): string;
841857
}
842858
}

0 commit comments

Comments
 (0)