Skip to content

Commit 74c971c

Browse files
committed
Add publisher/subscription_event_type_is_supported
1 parent d78f9aa commit 74c971c

3 files changed

Lines changed: 190 additions & 0 deletions

File tree

lib/event_handler.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,85 @@ const SubscriptionEventType = {
5555
SUBSCRIPTION_MATCHED: 5,
5656
};
5757

58+
/**
59+
* Check if a publisher event type is supported by the active RMW implementation.
60+
*
61+
* Only available in ROS 2 Rolling and later, where the underlying rcl API
62+
* (`rcl_publisher_event_type_is_supported`) is provided.
63+
*
64+
* @param {number} eventType - A {@link PublisherEventType} value.
65+
* @return {boolean} True if the event type is supported by the active RMW
66+
* implementation, false otherwise.
67+
* @throws {OperationError} if invoked on a ROS distro older than Rolling, or
68+
* if eventType is not a valid {@link PublisherEventType} value.
69+
*/
70+
function isPublisherEventTypeSupported(eventType) {
71+
if (typeof rclnodejs.isPublisherEventTypeSupported !== 'function') {
72+
throw new OperationError(
73+
'isPublisherEventTypeSupported is only available in ROS 2 Rolling and later',
74+
{
75+
code: 'UNSUPPORTED_ROS_VERSION',
76+
entityType: 'publisher event type',
77+
details: {
78+
requiredVersion: 'rolling',
79+
currentVersion: DistroUtils.getDistroId(),
80+
},
81+
}
82+
);
83+
}
84+
if (
85+
typeof eventType !== 'number' ||
86+
!Object.values(PublisherEventType).includes(eventType)
87+
) {
88+
throw new OperationError(`Invalid PublisherEventType value: ${eventType}`, {
89+
code: 'INVALID_ARGUMENT',
90+
entityType: 'publisher event type',
91+
});
92+
}
93+
return rclnodejs.isPublisherEventTypeSupported(eventType);
94+
}
95+
96+
/**
97+
* Check if a subscription event type is supported by the active RMW implementation.
98+
*
99+
* Only available in ROS 2 Rolling and later, where the underlying rcl API
100+
* (`rcl_subscription_event_type_is_supported`) is provided.
101+
*
102+
* @param {number} eventType - A {@link SubscriptionEventType} value.
103+
* @return {boolean} True if the event type is supported by the active RMW
104+
* implementation, false otherwise.
105+
* @throws {OperationError} if invoked on a ROS distro older than Rolling, or
106+
* if eventType is not a valid {@link SubscriptionEventType} value.
107+
*/
108+
function isSubscriptionEventTypeSupported(eventType) {
109+
if (typeof rclnodejs.isSubscriptionEventTypeSupported !== 'function') {
110+
throw new OperationError(
111+
'isSubscriptionEventTypeSupported is only available in ROS 2 Rolling and later',
112+
{
113+
code: 'UNSUPPORTED_ROS_VERSION',
114+
entityType: 'subscription event type',
115+
details: {
116+
requiredVersion: 'rolling',
117+
currentVersion: DistroUtils.getDistroId(),
118+
},
119+
}
120+
);
121+
}
122+
if (
123+
typeof eventType !== 'number' ||
124+
!Object.values(SubscriptionEventType).includes(eventType)
125+
) {
126+
throw new OperationError(
127+
`Invalid SubscriptionEventType value: ${eventType}`,
128+
{
129+
code: 'INVALID_ARGUMENT',
130+
entityType: 'subscription event type',
131+
}
132+
);
133+
}
134+
return rclnodejs.isSubscriptionEventTypeSupported(eventType);
135+
}
136+
58137
class EventHandler extends Entity {
59138
constructor(handle, callback, eventType, eventTypeName) {
60139
super(handle, null, null);
@@ -488,4 +567,6 @@ module.exports = {
488567
PublisherEventType,
489568
SubscriptionEventCallbacks,
490569
SubscriptionEventType,
570+
isPublisherEventTypeSupported,
571+
isSubscriptionEventTypeSupported,
491572
};

src/rcl_event_handle_bindings.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,26 @@ Napi::Value CreatePublisherEventHandle(const Napi::CallbackInfo& info) {
247247
return js_obj;
248248
}
249249

250+
#if ROS_VERSION >= 5000
251+
Napi::Value IsPublisherEventTypeSupported(const Napi::CallbackInfo& info) {
252+
Napi::Env env = info.Env();
253+
rcl_publisher_event_type_t event_type =
254+
static_cast<rcl_publisher_event_type_t>(
255+
info[0].As<Napi::Number>().Int32Value());
256+
return Napi::Boolean::New(env,
257+
rcl_publisher_event_type_is_supported(event_type));
258+
}
259+
260+
Napi::Value IsSubscriptionEventTypeSupported(const Napi::CallbackInfo& info) {
261+
Napi::Env env = info.Env();
262+
rcl_subscription_event_type_t event_type =
263+
static_cast<rcl_subscription_event_type_t>(
264+
info[0].As<Napi::Number>().Int32Value());
265+
return Napi::Boolean::New(
266+
env, rcl_subscription_event_type_is_supported(event_type));
267+
}
268+
#endif // ROS_VERSION >= 5000
269+
250270
Napi::Value TakeEvent(const Napi::CallbackInfo& info) {
251271
Napi::Env env = info.Env();
252272
RclHandle* event_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
@@ -288,6 +308,12 @@ Napi::Object InitEventHandleBindings(Napi::Env env, Napi::Object exports) {
288308
exports.Set("createPublisherEventHandle",
289309
Napi::Function::New(env, CreatePublisherEventHandle));
290310
exports.Set("takeEvent", Napi::Function::New(env, TakeEvent));
311+
#if ROS_VERSION >= 5000
312+
exports.Set("isPublisherEventTypeSupported",
313+
Napi::Function::New(env, IsPublisherEventTypeSupported));
314+
exports.Set("isSubscriptionEventTypeSupported",
315+
Napi::Function::New(env, IsSubscriptionEventTypeSupported));
316+
#endif // ROS_VERSION >= 5000
291317
return exports;
292318
}
293319

test/test-event-handle.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ const {
2424
PublisherEventCallbacks,
2525
PublisherEventType,
2626
SubscriptionEventType,
27+
isPublisherEventTypeSupported,
28+
isSubscriptionEventTypeSupported,
2729
} = require('../lib/event_handler.js');
2830

2931
describe('Event handle test suite prior to jazzy', function () {
@@ -46,6 +48,87 @@ describe('Event handle test suite prior to jazzy', function () {
4648
});
4749
});
4850

51+
describe('Event type is supported - native binding unavailable', function () {
52+
before(function () {
53+
if (
54+
typeof rclnodejsBinding.isPublisherEventTypeSupported === 'function' &&
55+
typeof rclnodejsBinding.isSubscriptionEventTypeSupported === 'function'
56+
) {
57+
this.skip();
58+
}
59+
});
60+
61+
it('isPublisherEventTypeSupported throws when native binding is missing', function () {
62+
assert.throws(() => {
63+
isPublisherEventTypeSupported(PublisherEventType.PUBLISHER_MATCHED);
64+
}, /isPublisherEventTypeSupported is only available in ROS 2 Rolling and later/);
65+
});
66+
67+
it('isSubscriptionEventTypeSupported throws when native binding is missing', function () {
68+
assert.throws(() => {
69+
isSubscriptionEventTypeSupported(
70+
SubscriptionEventType.SUBSCRIPTION_MATCHED
71+
);
72+
}, /isSubscriptionEventTypeSupported is only available in ROS 2 Rolling and later/);
73+
});
74+
});
75+
76+
describe('Event type is supported - native binding available', function () {
77+
before(function () {
78+
if (
79+
typeof rclnodejsBinding.isPublisherEventTypeSupported !== 'function' ||
80+
typeof rclnodejsBinding.isSubscriptionEventTypeSupported !== 'function'
81+
) {
82+
this.skip();
83+
}
84+
});
85+
86+
it('isPublisherEventTypeSupported returns a boolean for every event type', function () {
87+
for (const eventType of Object.values(PublisherEventType)) {
88+
const result = isPublisherEventTypeSupported(eventType);
89+
assert.strictEqual(typeof result, 'boolean');
90+
}
91+
});
92+
93+
it('isSubscriptionEventTypeSupported returns a boolean for every event type', function () {
94+
for (const eventType of Object.values(SubscriptionEventType)) {
95+
const result = isSubscriptionEventTypeSupported(eventType);
96+
assert.strictEqual(typeof result, 'boolean');
97+
}
98+
});
99+
100+
it('MATCHED events are reported as supported across RMW implementations', function () {
101+
assert.strictEqual(
102+
isPublisherEventTypeSupported(PublisherEventType.PUBLISHER_MATCHED),
103+
true
104+
);
105+
assert.strictEqual(
106+
isSubscriptionEventTypeSupported(
107+
SubscriptionEventType.SUBSCRIPTION_MATCHED
108+
),
109+
true
110+
);
111+
});
112+
113+
it('isPublisherEventTypeSupported rejects invalid event types', function () {
114+
assert.throws(() => {
115+
isPublisherEventTypeSupported(-1);
116+
}, /Invalid PublisherEventType value/);
117+
assert.throws(() => {
118+
isPublisherEventTypeSupported('matched');
119+
}, /Invalid PublisherEventType value/);
120+
});
121+
122+
it('isSubscriptionEventTypeSupported rejects invalid event types', function () {
123+
assert.throws(() => {
124+
isSubscriptionEventTypeSupported(999);
125+
}, /Invalid SubscriptionEventType value/);
126+
assert.throws(() => {
127+
isSubscriptionEventTypeSupported(undefined);
128+
}, /Invalid SubscriptionEventType value/);
129+
});
130+
});
131+
49132
describe('Event handle test suite', function () {
50133
this.timeout(5 * 1000);
51134
let node;

0 commit comments

Comments
 (0)