Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lib/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,14 @@ class Context {
}
return defaultContext;
}

/**
* Get the domain ID of this context.
* @returns {Number} domain ID of this context
*/
get domainId() {
return rclnodejs.getDomainId(this.handle);
}
}

Context._instances = [];
Expand Down
18 changes: 18 additions & 0 deletions lib/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,24 @@ class Node extends rclnodejs.ShadowNode {
return rclnodejs.countSubscribers(this.handle, expandedTopic);
}

/**
* Get the number of clients on a given service name.
* @param {string} serviceName - the service name
* @returns {Number}
*/
countClients(serviceName) {
return rclnodejs.countClients(this.handle, serviceName);
}

/**
* Get the number of services on a given service name.
* @param {string} serviceName - the service name
* @returns {Number}
*/
countServices(serviceName) {
return rclnodejs.countServices(this.handle, serviceName);
}

/**
* Get the list of parameter-overrides found on the commandline and
* in the NodeOptions.parameter_overrides property.
Expand Down
8 changes: 8 additions & 0 deletions lib/publisher.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ class Publisher extends Entity {
);
return new Publisher(handle, typeClass, topic, options);
}

/**
* Get the number of subscriptions to this publisher.
* @returns {number} The number of subscriptions
*/
get subscriptionCount() {
return rclnodejs.getSubscriptionCount(this._handle);
}
}

module.exports = Publisher;
8 changes: 8 additions & 0 deletions lib/subscription.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,14 @@ class Subscription extends Entity {
? rclnodejs.clearContentFilter(this.handle)
: true;
}

/**
* Get the number of publishers to this subscription.
* @returns {number} The number of publishers
*/
get publisherCount() {
return rclnodejs.getPublisherCount(this._handle);
}
}

module.exports = Subscription;
18 changes: 18 additions & 0 deletions src/rcl_context_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,29 @@ Napi::Value IsContextValid(const Napi::CallbackInfo& info) {
return Napi::Boolean::New(env, is_valid);
}

Napi::Value GetDomainId(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();

RclHandle* context_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
rcl_context_t* context =
reinterpret_cast<rcl_context_t*>(context_handle->ptr());
size_t domain_id;
rcl_ret_t ret = rcl_context_get_domain_id(context, &domain_id);
if (RCL_RET_OK != ret) {
Napi::Error::New(env, rcl_get_error_string().str)
.ThrowAsJavaScriptException();
return env.Undefined();
}

return Napi::Number::New(env, domain_id);
}

Napi::Object InitContextBindings(Napi::Env env, Napi::Object exports) {
exports.Set("init", Napi::Function::New(env, Init));
exports.Set("shutdown", Napi::Function::New(env, Shutdown));
exports.Set("createContext", Napi::Function::New(env, CreateContext));
exports.Set("isContextValid", Napi::Function::New(env, IsContextValid));
exports.Set("getDomainId", Napi::Function::New(env, GetDomainId));
return exports;
}

Expand Down
32 changes: 0 additions & 32 deletions src/rcl_graph_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,36 +232,6 @@ Napi::Value GetNodeNames(const Napi::CallbackInfo& info) {
return result_list;
}

Napi::Value CountPublishers(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();

RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
std::string topic_name = info[1].As<Napi::String>().Utf8Value();

size_t count = 0;
THROW_ERROR_IF_NOT_EQUAL(
RCL_RET_OK, rcl_count_publishers(node, topic_name.c_str(), &count),
"Failed to count publishers.");

return Napi::Number::New(env, static_cast<int32_t>(count));
}

Napi::Value CountSubscribers(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();

RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
std::string topic_name = info[1].As<Napi::String>().Utf8Value();

size_t count = 0;
THROW_ERROR_IF_NOT_EQUAL(
RCL_RET_OK, rcl_count_subscribers(node, topic_name.c_str(), &count),
"Failed to count subscribers.");

return Napi::Number::New(env, static_cast<int32_t>(count));
}

Napi::Value ServiceServerIsAvailable(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();

Expand Down Expand Up @@ -292,8 +262,6 @@ Napi::Object InitGraphBindings(Napi::Env env, Napi::Object exports) {
exports.Set("getServiceNamesAndTypes",
Napi::Function::New(env, GetServiceNamesAndTypes));
exports.Set("getNodeNames", Napi::Function::New(env, GetNodeNames));
exports.Set("countPublishers", Napi::Function::New(env, CountPublishers));
exports.Set("countSubscribers", Napi::Function::New(env, CountSubscribers));
exports.Set("serviceServerIsAvailable",
Napi::Function::New(env, ServiceServerIsAvailable));
return exports;
Expand Down
64 changes: 64 additions & 0 deletions src/rcl_node_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,66 @@ Napi::Value ActionGetNamesAndTypes(const Napi::CallbackInfo& info) {
return result_list;
}

Napi::Value CountPublishers(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();

RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
std::string topic_name = info[1].As<Napi::String>().Utf8Value();

size_t count = 0;
THROW_ERROR_IF_NOT_EQUAL(
RCL_RET_OK, rcl_count_publishers(node, topic_name.c_str(), &count),
"Failed to count publishers.");

return Napi::Number::New(env, static_cast<int32_t>(count));
}

Napi::Value CountSubscribers(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();

RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
std::string topic_name = info[1].As<Napi::String>().Utf8Value();

size_t count = 0;
THROW_ERROR_IF_NOT_EQUAL(
RCL_RET_OK, rcl_count_subscribers(node, topic_name.c_str(), &count),
"Failed to count subscribers.");

return Napi::Number::New(env, static_cast<int32_t>(count));
}

Napi::Value CountClients(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();

rcl_node_t* node = reinterpret_cast<rcl_node_t*>(
RclHandle::Unwrap(info[0].As<Napi::Object>())->ptr());
std::string service_name = info[1].As<Napi::String>().Utf8Value();

size_t count = 0;
THROW_ERROR_IF_NOT_EQUAL(
rcl_count_clients(node, service_name.c_str(), &count), RCL_RET_OK,
rcl_get_error_string().str);

return Napi::Number::New(env, count);
}

Napi::Value CountServices(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();

rcl_node_t* node = reinterpret_cast<rcl_node_t*>(
RclHandle::Unwrap(info[0].As<Napi::Object>())->ptr());
std::string service_name = info[1].As<Napi::String>().Utf8Value();

size_t count = 0;
THROW_ERROR_IF_NOT_EQUAL(
rcl_count_services(node, service_name.c_str(), &count), RCL_RET_OK,
rcl_get_error_string().str);

return Napi::Number::New(env, count);
}

Napi::Object InitNodeBindings(Napi::Env env, Napi::Object exports) {
exports.Set("getParameterOverrides",
Napi::Function::New(env, GetParameterOverrides));
Expand All @@ -331,6 +391,10 @@ Napi::Object InitNodeBindings(Napi::Env env, Napi::Object exports) {
Napi::Function::New(env, ActionGetServerNamesAndTypesByNode));
exports.Set("actionGetNamesAndTypes",
Napi::Function::New(env, ActionGetNamesAndTypes));
exports.Set("countPublishers", Napi::Function::New(env, CountPublishers));
exports.Set("countSubscribers", Napi::Function::New(env, CountSubscribers));
exports.Set("countClients", Napi::Function::New(env, CountClients));
exports.Set("countServices", Napi::Function::New(env, CountServices));
return exports;
}

Expand Down
16 changes: 16 additions & 0 deletions src/rcl_publisher_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,27 @@ Napi::Value PublishRawMessage(const Napi::CallbackInfo& info) {
return env.Undefined();
}

Napi::Value GetSubscriptionCount(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();

rcl_publisher_t* publisher = reinterpret_cast<rcl_publisher_t*>(
RclHandle::Unwrap(info[0].As<Napi::Object>())->ptr());

size_t count = 0;
THROW_ERROR_IF_NOT_EQUAL(
rcl_publisher_get_subscription_count(publisher, &count), RCL_RET_OK,
rcl_get_error_string().str);

return Napi::Number::New(env, count);
}

Napi::Object InitPublisherBindings(Napi::Env env, Napi::Object exports) {
exports.Set("createPublisher", Napi::Function::New(env, CreatePublisher));
exports.Set("publish", Napi::Function::New(env, Publish));
exports.Set("getPublisherTopic", Napi::Function::New(env, GetPublisherTopic));
exports.Set("publishRawMessage", Napi::Function::New(env, PublishRawMessage));
exports.Set("getSubscriptionCount",
Napi::Function::New(env, GetSubscriptionCount));
return exports;
}

Expand Down
15 changes: 15 additions & 0 deletions src/rcl_subscription_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,20 @@ Napi::Value ClearContentFilter(const Napi::CallbackInfo& info) {
#endif
}

Napi::Value GetPublisherCount(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();

rcl_subscription_t* subscription = reinterpret_cast<rcl_subscription_t*>(
RclHandle::Unwrap(info[0].As<Napi::Object>())->ptr());

size_t count = 0;
THROW_ERROR_IF_NOT_EQUAL(
rcl_subscription_get_publisher_count(subscription, &count), RCL_RET_OK,
rcl_get_error_string().str);

return Napi::Number::New(env, count);
}

Napi::Object InitSubscriptionBindings(Napi::Env env, Napi::Object exports) {
exports.Set("rclTake", Napi::Function::New(env, RclTake));
exports.Set("createSubscription",
Expand All @@ -314,6 +328,7 @@ Napi::Object InitSubscriptionBindings(Napi::Env env, Napi::Object exports) {
exports.Set("setContentFilter", Napi::Function::New(env, SetContentFilter));
exports.Set("clearContentFilter",
Napi::Function::New(env, ClearContentFilter));
exports.Set("getPublisherCount", Napi::Function::New(env, GetPublisherCount));
return exports;
}

Expand Down
6 changes: 6 additions & 0 deletions test/test-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,10 @@ describe('context test suite', function () {
context.shutdown();
assert.strictEqual(context.nodes.length, 0);
});

it('context number id', async function () {
let context = new rclnodejs.Context();
await rclnodejs.init(context);
assert.strictEqual(typeof context.domainId, 'number');
});
});
17 changes: 17 additions & 0 deletions test/test-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,23 @@ describe('rcl node methods testing', function () {
await assertUtils.createDelay(500);
assert.strictEqual(node.countSubscribers('chatter'), 2);
});

it('node.countClients', function () {
const node = rclnodejs.createNode('publisher_node');
const AddTwoInts = 'example_interfaces/srv/AddTwoInts';
node.createClient(AddTwoInts, 'add_two_ints');
assert.strictEqual(node.countClients('/add_two_ints'), 1);

node.createClient(AddTwoInts, 'add_two_ints');
assert.strictEqual(node.countClients('/add_two_ints'), 2);
});

it('node.countServices', function () {
const node = rclnodejs.createNode('publisher_node');
const AddTwoInts = 'example_interfaces/srv/AddTwoInts';
node.createService(AddTwoInts, 'add_two_ints', (req) => {});
assert.strictEqual(node.countServices('/add_two_ints'), 1);
});
});

describe('topic & serviceName getter/setter', function () {
Expand Down
9 changes: 9 additions & 0 deletions test/test-publisher.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

'use strict';

const assert = require('assert');
const rclnodejs = require('../index.js');

describe('rclnodejs publisher test suite', function () {
Expand Down Expand Up @@ -42,4 +43,12 @@ describe('rclnodejs publisher test suite', function () {
publisher.publish(msg);
rclnodejs.spin(node);
});

it('Test count of subscriptions', function () {
const node = rclnodejs.createNode('publisher_node');
const String = 'std_msgs/msg/String';
const publisher = node.createPublisher(String, 'topic');
node.createSubscription(String, 'topic', (msg) => {});
assert.strictEqual(publisher.subscriptionCount, 1);
});
});
38 changes: 38 additions & 0 deletions test/test-subscription.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) 2025, The Robot Web Tools Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

const assert = require('assert');
const rclnodejs = require('../index.js');

describe('rclnodejs subscription test suite', function () {
this.timeout(60 * 1000);

beforeEach(function () {
return rclnodejs.init();
});

afterEach(function () {
rclnodejs.shutdown();
});

it('Test count of subscription', function () {
const node = rclnodejs.createNode('publisher_node');
const String = 'std_msgs/msg/String';
node.createPublisher(String, 'topic');
const subscription = node.createSubscription(String, 'topic', (msg) => {});
assert.strictEqual(subscription.publisherCount, 1);
});
});
Loading