rclnodejs 0.21.4 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,6 +26,7 @@ jobs:
26
26
  id: identify
27
27
  run: |
28
28
  if ${ROLLING_VAR} == true; then
29
+ # echo "::set-output name=distro::rolling"
29
30
  echo "::set-output name=distro::rolling"
30
31
  echo "::set-output name=linuxos::ubuntu-22.04"
31
32
  elif ${HUMBLE_VAR} == true; then
@@ -9,14 +9,14 @@ jobs:
9
9
  strategy:
10
10
  fail-fast: false
11
11
  matrix:
12
- node-version: [10.X, 12.x, 14.X, 16.X, 17.X]
12
+ node-version: [14.X, 16.X, 18.X, 19.X]
13
13
  ros_distribution:
14
14
  - humble
15
15
  - rolling
16
16
 
17
17
  steps:
18
18
  - name: Setup ROS2
19
- uses: ros-tooling/setup-ros@v0.4
19
+ uses: ros-tooling/setup-ros@v0.6
20
20
  with:
21
21
  required-ros-distributions: ${{ matrix.ros_distribution }}
22
22
 
@@ -26,7 +26,7 @@ jobs:
26
26
  - uses: actions/checkout@v3
27
27
 
28
28
  - name: Setup Node.js ${{ matrix.node-version }}
29
- uses: actions/setup-node@v2
29
+ uses: actions/setup-node@v3
30
30
  with:
31
31
  node-version: ${{ matrix.node-version }}
32
32
 
@@ -36,19 +36,18 @@ jobs:
36
36
  npm i
37
37
  npm test
38
38
 
39
- build-foxy-and-galactic: # foxy and galactic distros
39
+ build-foxy: # foxy distros
40
40
  runs-on: ubuntu-20.04
41
41
  strategy:
42
42
  fail-fast: false
43
43
  matrix:
44
- node-version: [10.X, 12.x, 14.X, 16.X, 17.X, 18.X, 19.X]
44
+ node-version: [14.X, 16.11.X, 18.X, 19.X]
45
45
  ros_distribution:
46
46
  - foxy
47
- - galactic
48
47
 
49
48
  steps:
50
49
  - name: Setup ROS2
51
- uses: ros-tooling/setup-ros@v0.4
50
+ uses: ros-tooling/setup-ros@v0.6
52
51
  with:
53
52
  required-ros-distributions: ${{ matrix.ros_distribution }}
54
53
 
@@ -58,7 +57,7 @@ jobs:
58
57
  - uses: actions/checkout@v3
59
58
 
60
59
  - name: Setup Node.js ${{ matrix.node-version }}
61
- uses: actions/setup-node@v2
60
+ uses: actions/setup-node@v3
62
61
  with:
63
62
  node-version: ${{ matrix.node-version }}
64
63
 
@@ -26,15 +26,15 @@ jobs:
26
26
  strategy:
27
27
  fail-fast: false
28
28
  matrix:
29
- node-version: [10.X, 12.X, 14.X, 16.11.X, 17.X, 18.X, 19.X]
29
+ node-version: [14.X, 16.X, 18.X, 19.X]
30
30
  steps:
31
31
  - name: Setup Node.js ${{ matrix.node-version }}
32
- uses: actions/setup-node@v2
32
+ uses: actions/setup-node@v3
33
33
  with:
34
34
  node-version: ${{ matrix.node-version }}
35
35
 
36
36
  - name: Setup ROS2
37
- uses: ros-tooling/setup-ros@v0.4
37
+ uses: ros-tooling/setup-ros@v0.6
38
38
  with:
39
39
  required-ros-distributions: ${{ needs.identify-ros-distro.outputs.distro }}
40
40
 
@@ -10,20 +10,19 @@ jobs:
10
10
  strategy:
11
11
  fail-fast: false
12
12
  matrix:
13
- node-version: [10.X, 12.X, 14.X, 16.11.X, 17.X, 18.X, 19.X]
13
+ node-version: [14.21.2, 16.19.0, 18.14.1, 19.X]
14
14
  ros_distribution:
15
- # - foxy
16
- - galactic
15
+ - foxy
17
16
  - humble
18
17
  - rolling
19
18
  steps:
20
19
  - name: Setup Node.js ${{ matrix.node-version }}
21
- uses: actions/setup-node@v2
20
+ uses: actions/setup-node@v3
22
21
  with:
23
22
  node-version: ${{ matrix.node-version }}
24
23
 
25
24
  - name: Setup ROS2
26
- uses: ros-tooling/setup-ros@v0.4
25
+ uses: ros-tooling/setup-ros@v0.6
27
26
  with:
28
27
  required-ros-distributions: ${{ matrix.ros_distribution }}
29
28
 
@@ -45,8 +44,11 @@ jobs:
45
44
  call "c:\dev\${{ matrix.ros_distribution }}\ros2-windows\setup.bat"
46
45
  npm i
47
46
 
47
+ # On the windows/foxy combination the Eclipse CycloneDDS RMW implementation is used to workaround
48
+ # an error when loading the default fastrtps ddl
48
49
  - name: Test rclnodejs
49
50
  shell: cmd
50
51
  run: |
51
52
  call "c:\dev\${{ matrix.ros_distribution }}\ros2-windows\setup.bat"
52
- npm test
53
+ cmd /c "if ${{ matrix.ros_distribution }}==foxy (set RMW_IMPLEMENTATION=rmw_cyclonedds_cpp&&npm test)"
54
+ cmd /c "if NOT ${{ matrix.ros_distribution }}==foxy (npm test)"
@@ -26,15 +26,17 @@ jobs:
26
26
  strategy:
27
27
  fail-fast: false
28
28
  matrix:
29
- node-version: [10.X, 12.X, 14.X, 16.11.X, 17.X, 18.X, 19.X]
29
+ # Explicit node versions are used to workaround an error
30
+ # where node-gyp fails due to some silly cacheing
31
+ node-version: [14.21.2, 16.19.0, 18.14.1, 19.X]
30
32
  steps:
31
33
  - name: Setup Node.js ${{ matrix.node-version }}
32
- uses: actions/setup-node@v2
34
+ uses: actions/setup-node@v3
33
35
  with:
34
36
  node-version: ${{ matrix.node-version }}
35
37
 
36
38
  - name: Setup ROS2
37
- uses: ros-tooling/setup-ros@v0.4
39
+ uses: ros-tooling/setup-ros@v0.6
38
40
  with:
39
41
  required-ros-distributions: ${{ needs.identify-ros-distro.outputs.distro }}
40
42
 
@@ -56,8 +58,11 @@ jobs:
56
58
  call "c:\dev\${{ needs.identify-ros-distro.outputs.distro }}\ros2-windows\setup.bat"
57
59
  npm i
58
60
 
61
+ # On the windows/foxy combination the Eclipse CycloneDDS RMW implementation is used to workaround
62
+ # an error when loading the default fastrtps ddl
59
63
  - name: Test rclnodejs
60
64
  shell: cmd
61
65
  run: |
62
66
  call "c:\dev\${{ needs.identify-ros-distro.outputs.distro }}\ros2-windows\setup.bat"
63
- npm test
67
+ cmd /c "if ${{ needs.identify-ros-distro.outputs.distro }}==foxy (set RMW_IMPLEMENTATION=rmw_cyclonedds_cpp&&npm test)"
68
+ cmd /c "if NOT ${{ needs.identify-ros-distro.outputs.distro }}==foxy (npm test)"
Binary file
package/binding.gyp CHANGED
@@ -82,6 +82,7 @@
82
82
  "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/rosidl_typesupport_interface/ ') + '/include/rosidl_typesupport_interface/')\")",
83
83
  "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/rcl_action/ ') + '/include/rcl_action/')\")",
84
84
  "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/action_msgs/ ') + '/include/action_msgs/')\")",
85
+ "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/service_msgs/ ') + '/include/service_msgs/')\")",
85
86
  "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/unique_identifier_msgs/ ') + '/include/unique_identifier_msgs/')\")",
86
87
  "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/builtin_interfaces/ ') + '/include/builtin_interfaces/')\")",
87
88
  "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/:/g, '/include/rcl_lifecycle/ ') + '/include/rcl_lifecycle/')\")",
@@ -129,10 +130,12 @@
129
130
  "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/rosidl_typesupport_interface ').replace(/\\\/g, '/') + '/include/rosidl_typesupport_interface')\")",
130
131
  "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/rcl_action ').replace(/\\\/g, '/') + '/include/rcl_action')\")",
131
132
  "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/action_msgs ').replace(/\\\/g, '/') + '/include/action_msgs')\")",
133
+ "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/service_msgs ').replace(/\\\/g, '/') + '/include/service_msgs')\")",
132
134
  "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/unique_identifier_msgs ').replace(/\\\/g, '/') + '/include/unique_identifier_msgs')\")",
133
135
  "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/builtin_interfaces ').replace(/\\\/g, '/') + '/include/builtin_interfaces')\")",
134
136
  "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/rcl_lifecycle ').replace(/\\\/g, '/') + '/include/rcl_lifecycle')\")",
135
137
  "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/lifecycle_msgs ').replace(/\\\/g, '/') + '/include/lifecycle_msgs')\")",
138
+ "<!@(node -e \"console.log(process.env.AMENT_PREFIX_PATH.replace(/;/g, '/include/rosidl_dynamic_typesupport ').replace(/\\\/g, '/') + '/include/rosidl_dynamic_typesupport')\")",
136
139
  ],
137
140
  }
138
141
  ]
package/index.js CHANGED
@@ -15,6 +15,7 @@
15
15
  'use strict';
16
16
 
17
17
  const DistroUtils = require('./lib/distro.js');
18
+ const RMWUtils = require('./lib/rmw.js');
18
19
  const { Clock, ROSClock } = require('./lib/clock.js');
19
20
  const ClockType = require('./lib/clock_type.js');
20
21
  const compareVersions = require('compare-versions');
@@ -136,6 +137,9 @@ let rcl = {
136
137
  /** {@link QoS} class */
137
138
  QoS: QoS,
138
139
 
140
+ /** {@link RMWUtils} */
141
+ RMWUtils: RMWUtils,
142
+
139
143
  /** {@link ROSClock} class */
140
144
  ROSClock: ROSClock,
141
145
 
@@ -363,14 +363,13 @@ class ActionClient extends Entity {
363
363
  * @return {undefined}
364
364
  */
365
365
  destroy() {
366
- if (this._destroyed) {
366
+ if (this.isDestroyed()) {
367
367
  return;
368
368
  }
369
369
 
370
370
  this._goalHandles.clear();
371
371
 
372
372
  this._node._destroyEntity(this, this._node._actionClients);
373
- this._destroyed = true;
374
373
  }
375
374
  }
376
375
 
@@ -440,7 +440,7 @@ class ActionServer extends Entity {
440
440
  * @return {undefined}
441
441
  */
442
442
  destroy() {
443
- if (this._destroyed) {
443
+ if (this.isDestroyed()) {
444
444
  return;
445
445
  }
446
446
 
@@ -451,7 +451,6 @@ class ActionServer extends Entity {
451
451
  this._goalHandles.clear();
452
452
 
453
453
  this._node._destroyEntity(this, this._node._actionServers);
454
- this._destroyed = true;
455
454
  }
456
455
  }
457
456
 
package/lib/client.js CHANGED
@@ -70,8 +70,9 @@ class Client extends Entity {
70
70
  this._sequenceNumberToCallbackMap.delete(sequenceNumber);
71
71
  callback(response.toPlainObject(this.typedArrayEnabled));
72
72
  } else {
73
- error(`Client has received an unexpected ${this._serviceName}
74
- response with sequence number ${sequenceNumber}.`);
73
+ throw new Error(
74
+ `Client has received an unexpected ${this._serviceName} with sequence number ${sequenceNumber}.`
75
+ );
75
76
  }
76
77
  }
77
78
 
package/lib/distro.js CHANGED
@@ -42,7 +42,7 @@ const DistroUtils = {
42
42
  * @return {number} Return the rclnodejs distro identifier
43
43
  */
44
44
  getDistroId: function (distroName) {
45
- const dname = distroName ? distroName : this.getDistroName();
45
+ const dname = distroName ? distroName.toLowerCase() : this.getDistroName();
46
46
 
47
47
  return DistroNameIdMap.has(dname)
48
48
  ? DistroNameIdMap.get(dname)
package/lib/entity.js CHANGED
@@ -14,16 +14,36 @@
14
14
 
15
15
  'use strict';
16
16
 
17
+ // Destroying an entity for which there is immediate i/o activity can
18
+ // results in a SEGFAULT. To mitigate this situation we hold a
19
+ // reference to released handles to prevent them from being
20
+ // GC'ed prematurely.
21
+ const OBSOLETE_HANDLES = new Set();
22
+ function registerObsoleteHandle(handle) {
23
+ OBSOLETE_HANDLES.add(handle);
24
+ }
25
+
17
26
  /**
18
27
  * @class - Class representing a common object in RCL.
19
28
  * @ignore
20
29
  */
21
30
 
22
31
  class Entity {
32
+ /**
33
+ * Clears the internal short-lived cache of references to
34
+ * destroyed entities.
35
+ *
36
+ * @ignore
37
+ */
38
+ static _gcHandles() {
39
+ OBSOLETE_HANDLES.clear();
40
+ }
41
+
23
42
  constructor(handle, typeClass, options) {
24
43
  this._handle = handle;
25
44
  this._typeClass = typeClass;
26
45
  this._options = options;
46
+ this._destroyed = false;
27
47
  }
28
48
 
29
49
  get handle() {
@@ -49,6 +69,26 @@ class Entity {
49
69
  get typeClass() {
50
70
  return this._typeClass;
51
71
  }
72
+
73
+ /**
74
+ * Release all resources held by this entity.
75
+ * Do not call this method directly.
76
+ */
77
+ _destroy() {
78
+ if (this.isDestroyed()) return;
79
+
80
+ this._destroyed = true;
81
+ this.handle.release();
82
+ registerObsoleteHandle(this._handle);
83
+ }
84
+
85
+ /**
86
+ * Test if this entity has been destroyed and resources released.
87
+ * @returns {boolean} - true when destroyed has previously been called.
88
+ */
89
+ isDestroyed() {
90
+ return this._destroyed;
91
+ }
52
92
  }
53
93
 
54
94
  module.exports = Entity;
package/lib/node.js CHANGED
@@ -38,6 +38,7 @@ const Service = require('./service.js');
38
38
  const Subscription = require('./subscription.js');
39
39
  const TimeSource = require('./time_source.js');
40
40
  const Timer = require('./timer.js');
41
+ const Entity = require('./entity.js');
41
42
 
42
43
  // Parameter event publisher constants
43
44
  const PARAMETER_EVENT_MSG_TYPE = 'rcl_interfaces/msg/ParameterEvent';
@@ -148,26 +149,26 @@ class Node extends rclnodejs.ShadowNode {
148
149
  }
149
150
 
150
151
  execute(handles) {
151
- let timersReady = this._timers.filter(
152
- (timer) => handles.indexOf(timer.handle) !== -1
152
+ let timersReady = this._timers.filter((timer) =>
153
+ handles.includes(timer.handle)
153
154
  );
154
- let guardsReady = this._guards.filter(
155
- (guard) => handles.indexOf(guard.handle) !== -1
155
+ let guardsReady = this._guards.filter((guard) =>
156
+ handles.includes(guard.handle)
156
157
  );
157
- let subscriptionsReady = this._subscriptions.filter(
158
- (subscription) => handles.indexOf(subscription.handle) !== -1
158
+ let subscriptionsReady = this._subscriptions.filter((subscription) =>
159
+ handles.includes(subscription.handle)
159
160
  );
160
- let clientsReady = this._clients.filter(
161
- (client) => handles.indexOf(client.handle) !== -1
161
+ let clientsReady = this._clients.filter((client) =>
162
+ handles.includes(client.handle)
162
163
  );
163
- let servicesReady = this._services.filter(
164
- (service) => handles.indexOf(service.handle) !== -1
164
+ let servicesReady = this._services.filter((service) =>
165
+ handles.includes(service.handle)
165
166
  );
166
- let actionClientsReady = this._actionClients.filter(
167
- (actionClient) => handles.indexOf(actionClient.handle) !== -1
167
+ let actionClientsReady = this._actionClients.filter((actionClient) =>
168
+ handles.includes(actionClient.handle)
168
169
  );
169
- let actionServersReady = this._actionServers.filter(
170
- (actionServer) => handles.indexOf(actionServer.handle) !== -1
170
+ let actionServersReady = this._actionServers.filter((actionServer) =>
171
+ handles.includes(actionServer.handle)
171
172
  );
172
173
 
173
174
  timersReady.forEach((timer) => {
@@ -177,14 +178,16 @@ class Node extends rclnodejs.ShadowNode {
177
178
  }
178
179
  });
179
180
 
180
- subscriptionsReady.forEach((subscription) => {
181
+ for (const subscription of subscriptionsReady) {
182
+ if (subscription.isDestroyed()) continue;
181
183
  if (subscription.isRaw) {
182
184
  let rawMessage = rclnodejs.rclTakeRaw(subscription.handle);
183
185
  if (rawMessage) {
184
186
  subscription.processResponse(rawMessage);
185
187
  }
186
- return;
188
+ continue;
187
189
  }
190
+
188
191
  this._runWithMessageType(
189
192
  subscription.typeClass,
190
193
  (message, deserialize) => {
@@ -194,13 +197,16 @@ class Node extends rclnodejs.ShadowNode {
194
197
  }
195
198
  }
196
199
  );
197
- });
200
+ }
201
+
202
+ for (const guard of guardsReady) {
203
+ if (guard.isDestroyed()) continue;
198
204
 
199
- guardsReady.forEach((guard) => {
200
205
  guard.callback();
201
- });
206
+ }
202
207
 
203
- clientsReady.forEach((client) => {
208
+ for (const client of clientsReady) {
209
+ if (client.isDestroyed()) continue;
204
210
  this._runWithMessageType(
205
211
  client.typeClass.Response,
206
212
  (message, deserialize) => {
@@ -213,9 +219,10 @@ class Node extends rclnodejs.ShadowNode {
213
219
  }
214
220
  }
215
221
  );
216
- });
222
+ }
217
223
 
218
- servicesReady.forEach((service) => {
224
+ for (const service of servicesReady) {
225
+ if (service.isDestroyed()) continue;
219
226
  this._runWithMessageType(
220
227
  service.typeClass.Request,
221
228
  (message, deserialize) => {
@@ -229,9 +236,11 @@ class Node extends rclnodejs.ShadowNode {
229
236
  }
230
237
  }
231
238
  );
232
- });
239
+ }
240
+
241
+ for (const actionClient of actionClientsReady) {
242
+ if (actionClient.isDestroyed()) continue;
233
243
 
234
- actionClientsReady.forEach((actionClient) => {
235
244
  const properties = actionClient.handle.properties;
236
245
 
237
246
  if (properties.isGoalResponseReady) {
@@ -242,7 +251,7 @@ class Node extends rclnodejs.ShadowNode {
242
251
  actionClient.handle,
243
252
  message
244
253
  );
245
- if (sequence != null) {
254
+ if (sequence != undefined) {
246
255
  actionClient.processGoalResponse(sequence, deserialize());
247
256
  }
248
257
  }
@@ -257,7 +266,7 @@ class Node extends rclnodejs.ShadowNode {
257
266
  actionClient.handle,
258
267
  message
259
268
  );
260
- if (sequence != null) {
269
+ if (sequence != undefined) {
261
270
  actionClient.processCancelResponse(sequence, deserialize());
262
271
  }
263
272
  }
@@ -272,7 +281,7 @@ class Node extends rclnodejs.ShadowNode {
272
281
  actionClient.handle,
273
282
  message
274
283
  );
275
- if (sequence != null) {
284
+ if (sequence != undefined) {
276
285
  actionClient.processResultResponse(sequence, deserialize());
277
286
  }
278
287
  }
@@ -308,9 +317,11 @@ class Node extends rclnodejs.ShadowNode {
308
317
  }
309
318
  );
310
319
  }
311
- });
320
+ }
321
+
322
+ for (const actionServer of actionServersReady) {
323
+ if (actionServer.isDestroyed()) continue;
312
324
 
313
- actionServersReady.forEach((actionServer) => {
314
325
  const properties = actionServer.handle.properties;
315
326
 
316
327
  if (properties.isGoalRequestReady) {
@@ -371,7 +382,11 @@ class Node extends rclnodejs.ShadowNode {
371
382
  }
372
383
  GoalInfoArray.freeArray(message);
373
384
  }
374
- });
385
+ }
386
+
387
+ // At this point it is safe to clear the cache of any
388
+ // destroyed entity references
389
+ Entity._gcHandles();
375
390
  }
376
391
 
377
392
  /**
@@ -448,11 +463,19 @@ class Node extends rclnodejs.ShadowNode {
448
463
  }
449
464
 
450
465
  _destroyEntity(entity, array, syncHandles = true) {
466
+ if (entity['isDestroyed'] && entity.isDestroyed()) return;
467
+
451
468
  this._removeEntityFromArray(entity, array);
452
469
  if (syncHandles) {
453
470
  this.syncHandles();
454
471
  }
455
- entity.handle.release();
472
+
473
+ if (entity['_destroy']) {
474
+ entity._destroy();
475
+ } else {
476
+ // guards and timers
477
+ entity.handle.release();
478
+ }
456
479
  }
457
480
 
458
481
  _validateOptions(options) {
@@ -464,12 +487,7 @@ class Node extends rclnodejs.ShadowNode {
464
487
  }
465
488
 
466
489
  if (options === undefined) {
467
- options = {
468
- enableTypedArray: true,
469
- isRaw: false,
470
- qos: QoS.profileDefault,
471
- };
472
- return options;
490
+ return Node.getDefaultOptions();
473
491
  }
474
492
 
475
493
  if (options.enableTypedArray === undefined) {
@@ -608,7 +626,7 @@ class Node extends rclnodejs.ShadowNode {
608
626
  */
609
627
 
610
628
  /**
611
- * Create a Subscription.
629
+ * Create a Subscription with optional content-filtering.
612
630
  * @param {function|string|object} typeClass - The ROS message class,
613
631
  OR a string representing the message class, e.g. 'std_msgs/msg/String',
614
632
  OR an object representing the message class, e.g. {package: 'std_msgs', type: 'msg', name: 'String'}
@@ -617,9 +635,18 @@ class Node extends rclnodejs.ShadowNode {
617
635
  * @param {boolean} options.enableTypedArray - The topic will use TypedArray if necessary, default: true.
618
636
  * @param {QoS} options.qos - ROS Middleware "quality of service" settings for the subscription, default: QoS.profileDefault.
619
637
  * @param {boolean} options.isRaw - The topic is serialized when true, default: false.
638
+ * @param {object} [options.contentFilter=undefined] - The content-filter, default: undefined.
639
+ * Confirm that your RMW supports content-filtered topics before use.
640
+ * @param {string} options.contentFilter.expression - Specifies the criteria to select the data samples of
641
+ * interest. It is similar to the WHERE part of an SQL clause.
642
+ * @param {string[]} [options.contentFilter.parameters=undefined] - Array of strings that give values to
643
+ * the ‘parameters’ (i.e., "%n" tokens) in the filter_expression. The number of supplied parameters must
644
+ * fit with the requested values in the filter_expression (i.e., the number of %n tokens). default: undefined.
620
645
  * @param {SubscriptionCallback} callback - The callback to be call when receiving the topic subscribed. The topic will be an instance of null-terminated Buffer when options.isRaw is true.
621
646
  * @return {Subscription} - An instance of Subscription.
647
+ * @throws {ERROR} - May throw an RMW error if content-filter is malformed.
622
648
  * @see {@link SubscriptionCallback}
649
+ * @see {@link https://www.omg.org/spec/DDS/1.4/PDF|Content-filter details at DDS 1.4 specification, Annex B}
623
650
  */
624
651
  createSubscription(typeClass, topic, options, callback) {
625
652
  if (typeof typeClass === 'string' || typeof typeClass === 'object') {
@@ -1645,4 +1672,25 @@ class Node extends rclnodejs.ShadowNode {
1645
1672
  }
1646
1673
  }
1647
1674
 
1675
+ /**
1676
+ * Create an Options instance initialized with default values.
1677
+ * @returns {Options} - The new initialized instance.
1678
+ * @static
1679
+ * @example
1680
+ * {
1681
+ * enableTypedArray: true,
1682
+ * isRaw: false,
1683
+ * qos: QoS.profileDefault,
1684
+ * contentFilter: undefined,
1685
+ * }
1686
+ */
1687
+ Node.getDefaultOptions = function () {
1688
+ return {
1689
+ enableTypedArray: true,
1690
+ isRaw: false,
1691
+ qos: QoS.profileDefault,
1692
+ contentFilter: undefined,
1693
+ };
1694
+ };
1695
+
1648
1696
  module.exports = Node;
package/lib/rmw.js ADDED
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ const DistroUtils = require('./distro');
4
+
5
+ const RMWNames = {
6
+ FASTRTPS: 'rmw_fastrtps_cpp',
7
+ CONNEXT: 'rmw_connext_cpp',
8
+ CYCLONEDDS: 'rmw_cyclonedds_cpp',
9
+ GURUMDDS: 'rmw_gurumdds_cpp',
10
+ };
11
+
12
+ const DefaultRosRMWNameMap = new Map();
13
+ DefaultRosRMWNameMap.set('eloquent', RMWNames.FASTRTPS);
14
+ DefaultRosRMWNameMap.set('foxy', RMWNames.FASTRTPS);
15
+ DefaultRosRMWNameMap.set('galactic', RMWNames.CYCLONEDDS);
16
+ DefaultRosRMWNameMap.set('humble', RMWNames.FASTRTPS);
17
+ DefaultRosRMWNameMap.set('rolling', RMWNames.FASTRTPS);
18
+
19
+ const RMWUtils = {
20
+ RMWNames: RMWNames,
21
+
22
+ getRMWName: function () {
23
+ return process.env.RMW_IMPLEMENTATION
24
+ ? process.env.RMW_IMPLEMENTATION
25
+ : DefaultRosRMWNameMap.get(DistroUtils.getDistroName());
26
+ },
27
+ };
28
+
29
+ module.exports = RMWUtils;