rclnodejs 1.2.0 → 1.3.0

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.
package/README.md CHANGED
@@ -45,7 +45,7 @@ npm i rclnodejs@x.y.z
45
45
 
46
46
  | RCLNODEJS Version | Compatible ROS 2 LTS |
47
47
  | :----------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
48
- | latest version (currently [v1.2.0](https://github.com/RobotWebTools/rclnodejs/tree/1.2.0)) | [Kilted](https://github.com/RobotWebTools/rclnodejs/tree/kilted)<br>[Jazzy](https://github.com/RobotWebTools/rclnodejs/tree/jazzy)<br>[Humble](https://github.com/RobotWebTools/rclnodejs/tree/humble-hawksbill) |
48
+ | latest version (currently [v1.3.0](https://github.com/RobotWebTools/rclnodejs/tree/1.3.0)) | [Kilted](https://github.com/RobotWebTools/rclnodejs/tree/kilted)<br>[Jazzy](https://github.com/RobotWebTools/rclnodejs/tree/jazzy)<br>[Humble](https://github.com/RobotWebTools/rclnodejs/tree/humble-hawksbill) |
49
49
 
50
50
  ## Documentation
51
51
 
package/binding.gyp CHANGED
@@ -35,6 +35,7 @@
35
35
  './src/rcl_names_bindings.cpp',
36
36
  './src/rcl_node_bindings.cpp',
37
37
  './src/rcl_publisher_bindings.cpp',
38
+ './src/rcl_serialization_bindings.cpp',
38
39
  './src/rcl_service_bindings.cpp',
39
40
  './src/rcl_subscription_bindings.cpp',
40
41
  './src/rcl_time_point_bindings.cpp',
package/index.js CHANGED
@@ -53,6 +53,10 @@ const {
53
53
  getActionNamesAndTypes,
54
54
  } = require('./lib/action/graph.js');
55
55
  const ServiceIntrospectionStates = require('./lib/service_introspection.js');
56
+ const {
57
+ serializeMessage,
58
+ deserializeMessage,
59
+ } = require('./lib/serialization.js');
56
60
 
57
61
  /**
58
62
  * Get the version of the generator that was used for the currently present interfaces.
@@ -183,12 +187,22 @@ let rcl = {
183
187
  /** {@link getActionNamesAndTypes} function */
184
188
  getActionNamesAndTypes: getActionNamesAndTypes,
185
189
 
190
+ /** {@link serializeMessage} function */
191
+ serializeMessage: serializeMessage,
192
+
193
+ /** {@link deserializeMessage} function */
194
+ deserializeMessage: deserializeMessage,
195
+
186
196
  /**
187
197
  * Create and initialize a node.
188
198
  * @param {string} nodeName - The name used to register in ROS.
189
199
  * @param {string} [namespace=''] - The namespace used in ROS.
190
200
  * @param {Context} [context=Context.defaultContext()] - The context to create the node in.
191
201
  * @param {NodeOptions} [options=NodeOptions.defaultOptions] - The options to configure the new node behavior.
202
+ * @param {Array} [args=[]] - The arguments to pass to the node.
203
+ * @param {boolean} [useGlobalArguments=true] - If true, the node will use the global arguments
204
+ * from the context, otherwise it will only use the arguments
205
+ * passed in the args parameter.
192
206
  * @return {Node} A new instance of the specified node.
193
207
  * @throws {Error} If the given context is not registered.
194
208
  * @deprecated since 0.18.0, Use new Node constructor.
@@ -197,9 +211,18 @@ let rcl = {
197
211
  nodeName,
198
212
  namespace = '',
199
213
  context = Context.defaultContext(),
200
- options = NodeOptions.defaultOptions
214
+ options = NodeOptions.defaultOptions,
215
+ args = [],
216
+ useGlobalArguments = true
201
217
  ) {
202
- return new this.Node(nodeName, namespace, context, options);
218
+ return new this.Node(
219
+ nodeName,
220
+ namespace,
221
+ context,
222
+ options,
223
+ args,
224
+ useGlobalArguments
225
+ );
203
226
  },
204
227
 
205
228
  /**
@@ -255,7 +278,7 @@ let rcl = {
255
278
  throw new TypeError('argv elements must be strings (and not null).');
256
279
  }
257
280
 
258
- rclnodejs.init(context.handle, argv);
281
+ rclnodejs.init(context.handle, argv, context._domainId);
259
282
 
260
283
  if (_rosVersionChecked) {
261
284
  // no further processing required
package/lib/context.js CHANGED
@@ -63,11 +63,13 @@ class Context {
63
63
  * Call rcl.init(context) to initialize this context state for
64
64
  * use in creating nodes, etc.
65
65
  * @constructor
66
+ * @param {bigint} - Optional, The domain ID of this context.
66
67
  */
67
- constructor() {
68
+ constructor(domainId) {
68
69
  this._handle = rclnodejs.createContext();
69
70
  this._isShutdown = false;
70
71
  this._nodes = [];
72
+ this._domainId = domainId;
71
73
  Context._instances.push(this);
72
74
  }
73
75
 
@@ -222,7 +224,7 @@ class Context {
222
224
 
223
225
  /**
224
226
  * Get the domain ID of this context.
225
- * @returns {Number} domain ID of this context
227
+ * @returns {bigint} domain ID of this context
226
228
  */
227
229
  get domainId() {
228
230
  return rclnodejs.getDomainId(this.handle);
package/lib/lifecycle.js CHANGED
@@ -600,6 +600,15 @@ class LifecycleNode extends Node {
600
600
  return rclnodejs.isInitialized(this._stateMachineHandle);
601
601
  }
602
602
 
603
+ /**
604
+ * Log the state machine data.
605
+ *
606
+ * @returns {undefined} void.
607
+ */
608
+ print() {
609
+ rclnodejs.print(this._stateMachineHandle);
610
+ }
611
+
603
612
  /**
604
613
  * The GetState service handler.
605
614
  * @param {Object} request - The GetState service request.
package/lib/node.js CHANGED
@@ -43,6 +43,7 @@ const TypeDescriptionService = require('./type_description_service.js');
43
43
  const Entity = require('./entity.js');
44
44
  const { SubscriptionEventCallbacks } = require('../lib/event_handler.js');
45
45
  const { PublisherEventCallbacks } = require('../lib/event_handler.js');
46
+ const { validateFullTopicName } = require('./validator.js');
46
47
 
47
48
  // Parameter event publisher constants
48
49
  const PARAMETER_EVENT_MSG_TYPE = 'rcl_interfaces/msg/ParameterEvent';
@@ -66,7 +67,9 @@ class Node extends rclnodejs.ShadowNode {
66
67
  nodeName,
67
68
  namespace = '',
68
69
  context = Context.defaultContext(),
69
- options = NodeOptions.defaultOptions
70
+ options = NodeOptions.defaultOptions,
71
+ args = [],
72
+ useGlobalArguments = true
70
73
  ) {
71
74
  super();
72
75
 
@@ -74,7 +77,7 @@ class Node extends rclnodejs.ShadowNode {
74
77
  throw new TypeError('Invalid argument.');
75
78
  }
76
79
 
77
- this._init(nodeName, namespace, options, context);
80
+ this._init(nodeName, namespace, options, context, args, useGlobalArguments);
78
81
  debug(
79
82
  'Finish initializing node, name = %s and namespace = %s.',
80
83
  nodeName,
@@ -82,8 +85,14 @@ class Node extends rclnodejs.ShadowNode {
82
85
  );
83
86
  }
84
87
 
85
- _init(name, namespace, options, context) {
86
- this.handle = rclnodejs.createNode(name, namespace, context.handle);
88
+ _init(name, namespace, options, context, args, useGlobalArguments) {
89
+ this.handle = rclnodejs.createNode(
90
+ name,
91
+ namespace,
92
+ context.handle,
93
+ args,
94
+ useGlobalArguments
95
+ );
87
96
  Object.defineProperty(this, 'handle', {
88
97
  configurable: false,
89
98
  writable: false,
@@ -1064,27 +1073,57 @@ class Node extends rclnodejs.ShadowNode {
1064
1073
  }
1065
1074
 
1066
1075
  /**
1067
- * Get a list of publishers on a given topic.
1068
- * @param {string} topic - the topic name to get the publishers for.
1069
- * @param {boolean} noDemangle - if `true`, `topic_name` needs to be a valid middleware topic name,
1070
- * otherwise it should be a valid ROS topic name.
1076
+ * Return a list of publishers on a given topic.
1077
+ *
1078
+ * The returned parameter is a list of TopicEndpointInfo objects, where each will contain
1079
+ * the node name, node namespace, topic type, topic endpoint's GID, and its QoS profile.
1080
+ *
1081
+ * When the `no_mangle` parameter is `true`, the provided `topic` should be a valid
1082
+ * topic name for the middleware (useful when combining ROS with native middleware (e.g. DDS)
1083
+ * apps). When the `no_mangle` parameter is `false`, the provided `topic` should
1084
+ * follow ROS topic name conventions.
1085
+ *
1086
+ * `topic` may be a relative, private, or fully qualified topic name.
1087
+ * A relative or private topic will be expanded using this node's namespace and name.
1088
+ * The queried `topic` is not remapped.
1089
+ *
1090
+ * @param {string} topic - The topic on which to find the publishers.
1091
+ * @param {boolean} [noDemangle=false] - If `true`, `topic` needs to be a valid middleware topic
1092
+ * name, otherwise it should be a valid ROS topic name. Defaults to `false`.
1071
1093
  * @returns {Array} - list of publishers
1072
1094
  */
1073
- getPublishersInfoByTopic(topic, noDemangle) {
1074
- return rclnodejs.getPublishersInfoByTopic(this.handle, topic, noDemangle);
1095
+ getPublishersInfoByTopic(topic, noDemangle = false) {
1096
+ return rclnodejs.getPublishersInfoByTopic(
1097
+ this.handle,
1098
+ this._getValidatedTopic(topic, noDemangle),
1099
+ noDemangle
1100
+ );
1075
1101
  }
1076
1102
 
1077
1103
  /**
1078
- * Get a list of subscriptions on a given topic.
1079
- * @param {string} topic - the topic name to get the subscriptions for.
1080
- * @param {boolean} noDemangle - if `true`, `topic_name` needs to be a valid middleware topic name,
1081
- * otherwise it should be a valid ROS topic name.
1104
+ * Return a list of subscriptions on a given topic.
1105
+ *
1106
+ * The returned parameter is a list of TopicEndpointInfo objects, where each will contain
1107
+ * the node name, node namespace, topic type, topic endpoint's GID, and its QoS profile.
1108
+ *
1109
+ * When the `no_mangle` parameter is `true`, the provided `topic` should be a valid
1110
+ * topic name for the middleware (useful when combining ROS with native middleware (e.g. DDS)
1111
+ * apps). When the `no_mangle` parameter is `false`, the provided `topic` should
1112
+ * follow ROS topic name conventions.
1113
+ *
1114
+ * `topic` may be a relative, private, or fully qualified topic name.
1115
+ * A relative or private topic will be expanded using this node's namespace and name.
1116
+ * The queried `topic` is not remapped.
1117
+ *
1118
+ * @param {string} topic - The topic on which to find the subscriptions.
1119
+ * @param {boolean} [noDemangle=false] - If `true`, `topic` needs to be a valid middleware topic
1120
+ name, otherwise it should be a valid ROS topic name. Defaults to `false`.
1082
1121
  * @returns {Array} - list of subscriptions
1083
1122
  */
1084
- getSubscriptionsInfoByTopic(topic, noDemangle) {
1123
+ getSubscriptionsInfoByTopic(topic, noDemangle = false) {
1085
1124
  return rclnodejs.getSubscriptionsInfoByTopic(
1086
1125
  this.handle,
1087
- topic,
1126
+ this._getValidatedTopic(topic, noDemangle),
1088
1127
  noDemangle
1089
1128
  );
1090
1129
  }
@@ -1420,7 +1459,7 @@ class Node extends rclnodejs.ShadowNode {
1420
1459
  * Determine if a parameter descriptor exists.
1421
1460
  *
1422
1461
  * @param {string} name - The name of a descriptor to for.
1423
- * @return {boolean} - True if a descriptor has been declared; otherwise false.
1462
+ * @return {boolean} - true if a descriptor has been declared; otherwise false.
1424
1463
  */
1425
1464
  hasParameterDescriptor(name) {
1426
1465
  return !!this.getParameterDescriptor(name);
@@ -1684,6 +1723,42 @@ class Node extends rclnodejs.ShadowNode {
1684
1723
  return rclnodejs.getRMWImplementationIdentifier();
1685
1724
  }
1686
1725
 
1726
+ /**
1727
+ * Return a topic name expanded and remapped.
1728
+ * @param {string} topicName - Topic name to be expanded and remapped.
1729
+ * @param {boolean} [onlyExpand=false] - If `true`, remapping rules won't be applied.
1730
+ * @returns {string} - A fully qualified topic name.
1731
+ */
1732
+ resolveTopicName(topicName, onlyExpand = false) {
1733
+ if (typeof topicName !== 'string') {
1734
+ throw new TypeError('Invalid argument: expected string');
1735
+ }
1736
+ return rclnodejs.resolveName(
1737
+ this.handle,
1738
+ topicName,
1739
+ onlyExpand,
1740
+ /*isService=*/ false
1741
+ );
1742
+ }
1743
+
1744
+ /**
1745
+ * Return a service name expanded and remapped.
1746
+ * @param {string} service - Service name to be expanded and remapped.
1747
+ * @param {boolean} [onlyExpand=false] - If `true`, remapping rules won't be applied.
1748
+ * @returns {string} - A fully qualified service name.
1749
+ */
1750
+ resolveServiceName(service, onlyExpand = false) {
1751
+ if (typeof service !== 'string') {
1752
+ throw new TypeError('Invalid argument: expected string');
1753
+ }
1754
+ return rclnodejs.resolveName(
1755
+ this.handle,
1756
+ service,
1757
+ onlyExpand,
1758
+ /*isService=*/ true
1759
+ );
1760
+ }
1761
+
1687
1762
  // returns on 1st error or result {successful, reason}
1688
1763
  _validateParameters(parameters = [], declareParameterMode = false) {
1689
1764
  for (const parameter of parameters) {
@@ -1808,7 +1883,7 @@ class Node extends rclnodejs.ShadowNode {
1808
1883
  return result;
1809
1884
  });
1810
1885
 
1811
- Type.destoryRawROS(message);
1886
+ Type.destroyRawROS(message);
1812
1887
  }
1813
1888
 
1814
1889
  _addActionClient(actionClient) {
@@ -1820,6 +1895,19 @@ class Node extends rclnodejs.ShadowNode {
1820
1895
  this._actionServers.push(actionServer);
1821
1896
  this.syncHandles();
1822
1897
  }
1898
+
1899
+ _getValidatedTopic(topicName, noDemangle) {
1900
+ if (noDemangle) {
1901
+ return topicName;
1902
+ }
1903
+ const fqTopicName = rclnodejs.expandTopicName(
1904
+ topicName,
1905
+ this.name(),
1906
+ this.namespace()
1907
+ );
1908
+ validateFullTopicName(fqTopicName);
1909
+ return rclnodejs.remapTopicName(this.handle, fqTopicName);
1910
+ }
1823
1911
  }
1824
1912
 
1825
1913
  /**
@@ -0,0 +1,60 @@
1
+ // Copyright (c) 2025, The Robot Web Tools Contributors
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ 'use strict';
16
+
17
+ const rclnodejs = require('bindings')('rclnodejs');
18
+
19
+ class Serialization {
20
+ /**
21
+ * Serialize a message to a buffer.
22
+ * @param {object} message - The message to serialize.
23
+ * @param {function} typeClass - The class of the message type to serialize.
24
+ * @return {Buffer} The serialized message as a Buffer.
25
+ */
26
+ static serializeMessage(message, typeClass) {
27
+ if (!(message instanceof typeClass)) {
28
+ throw new TypeError('Message must be a valid ros2 message type');
29
+ }
30
+ return rclnodejs.serialize(
31
+ typeClass.type().pkgName,
32
+ typeClass.type().subFolder,
33
+ typeClass.type().interfaceName,
34
+ message.serialize()
35
+ );
36
+ }
37
+
38
+ /**
39
+ * Deserialize a message from a buffer.
40
+ * @param {Buffer} buffer - The buffer containing the serialized message.
41
+ * @param {function} typeClass - The class of the message type to deserialize into.
42
+ * @return {object} The deserialized message object.
43
+ */
44
+ static deserializeMessage(buffer, typeClass) {
45
+ if (!(buffer instanceof Buffer)) {
46
+ throw new TypeError('Buffer is required for deserialization');
47
+ }
48
+ const rosMsg = new typeClass();
49
+ rclnodejs.deserialize(
50
+ typeClass.type().pkgName,
51
+ typeClass.type().subFolder,
52
+ typeClass.type().interfaceName,
53
+ buffer,
54
+ rosMsg.toRawROS()
55
+ );
56
+ return rosMsg;
57
+ }
58
+ }
59
+
60
+ module.exports = Serialization;
@@ -18,6 +18,12 @@ const loader = require('./interface_loader.js');
18
18
  const rclnodejs = require('bindings')('rclnodejs');
19
19
  const Service = require('./service.js');
20
20
 
21
+ const {
22
+ ParameterType,
23
+ Parameter,
24
+ ParameterDescriptor,
25
+ } = require('../lib/parameter.js');
26
+
21
27
  // This class is used to create a TypeDescriptionService which can be used to
22
28
  // retrieve information about types used by the node’s publishers, subscribers,
23
29
  // services or actions.
@@ -32,10 +38,30 @@ class TypeDescriptionService {
32
38
  'type_description_interfaces/srv/GetTypeDescription'
33
39
  );
34
40
  this._typeDescriptionService = null;
41
+
42
+ this._enabled = false;
43
+ const startTypeDescriptionServiceParam = 'start_type_description_service';
44
+ if (!node.hasParameter(startTypeDescriptionServiceParam)) {
45
+ node.declareParameter(
46
+ new Parameter(
47
+ startTypeDescriptionServiceParam,
48
+ ParameterType.PARAMETER_BOOL,
49
+ true
50
+ ),
51
+ new ParameterDescriptor(
52
+ startTypeDescriptionServiceParam,
53
+ ParameterType.PARAMETER_BOOL,
54
+ 'If enabled, start the ~/get_type_description service.',
55
+ true
56
+ )
57
+ );
58
+ }
59
+ const param = node.getParameter(startTypeDescriptionServiceParam);
60
+ this._enabled = param.value;
35
61
  }
36
62
 
37
63
  start() {
38
- if (this._typeDescriptionService) {
64
+ if (!this._enabled || this._typeDescriptionService) {
39
65
  return;
40
66
  }
41
67
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rclnodejs",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "ROS2.0 JavaScript client with Node.js",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
@@ -506,7 +506,7 @@ class {{=objectWrapper}} {
506
506
  {{~}}
507
507
  }
508
508
 
509
- static destoryRawROS(msg) {
509
+ static destroyRawROS(msg) {
510
510
  {{=objectWrapper}}.freeStruct(msg.refObject);
511
511
  }
512
512
 
@@ -45,7 +45,7 @@ npm i rclnodejs@x.y.z
45
45
 
46
46
  | RCLNODEJS Version | Compatible ROS 2 LTS |
47
47
  | :----------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
48
- | latest version (currently [v1.2.0](https://github.com/RobotWebTools/rclnodejs/tree/1.2.0)) | [Kilted](https://github.com/RobotWebTools/rclnodejs/tree/kilted)<br>[Jazzy](https://github.com/RobotWebTools/rclnodejs/tree/jazzy)<br>[Humble](https://github.com/RobotWebTools/rclnodejs/tree/humble-hawksbill) |
48
+ | latest version (currently [v1.3.0](https://github.com/RobotWebTools/rclnodejs/tree/1.3.0)) | [Kilted](https://github.com/RobotWebTools/rclnodejs/tree/kilted)<br>[Jazzy](https://github.com/RobotWebTools/rclnodejs/tree/jazzy)<br>[Humble](https://github.com/RobotWebTools/rclnodejs/tree/humble-hawksbill) |
49
49
 
50
50
  ## Documentation
51
51
 
package/src/addon.cpp CHANGED
@@ -30,6 +30,7 @@
30
30
  #include "rcl_names_bindings.h"
31
31
  #include "rcl_node_bindings.h"
32
32
  #include "rcl_publisher_bindings.h"
33
+ #include "rcl_serialization_bindings.h"
33
34
  #include "rcl_service_bindings.h"
34
35
  #include "rcl_subscription_bindings.h"
35
36
  #include "rcl_time_point_bindings.h"
@@ -88,6 +89,7 @@ Napi::Object InitModule(Napi::Env env, Napi::Object exports) {
88
89
  rclnodejs::InitEventHandleBindings(env, exports);
89
90
  #endif
90
91
  rclnodejs::InitLifecycleBindings(env, exports);
92
+ rclnodejs::InitSerializationBindings(env, exports);
91
93
  rclnodejs::ShadowNode::Init(env, exports);
92
94
  rclnodejs::RclHandle::Init(env, exports);
93
95
 
package/src/macros.h CHANGED
@@ -23,17 +23,33 @@
23
23
  { \
24
24
  if (lhs op rhs) { \
25
25
  rcl_reset_error(); \
26
- Napi::Error::New(rclnodejs::GetEnv(), message) \
26
+ Napi::Error::New(env, message) \
27
27
  .ThrowAsJavaScriptException(); \
28
+ return env.Undefined(); \
28
29
  } \
29
30
  }
30
31
 
32
+ #define CHECK_OP_AND_THROW_ERROR_IF_NOT_TRUE_NO_RETURN(op, lhs, rhs, message) \
33
+ { \
34
+ if (lhs op rhs) { \
35
+ rcl_reset_error(); \
36
+ Napi::Error::New(env, message) \
37
+ .ThrowAsJavaScriptException(); \
38
+ } \
39
+ }
40
+
31
41
  #define THROW_ERROR_IF_NOT_EQUAL(lhs, rhs, message) \
32
42
  CHECK_OP_AND_THROW_ERROR_IF_NOT_TRUE(!=, lhs, rhs, message)
33
43
 
34
44
  #define THROW_ERROR_IF_EQUAL(lhs, rhs, message) \
35
45
  CHECK_OP_AND_THROW_ERROR_IF_NOT_TRUE(==, lhs, rhs, message)
36
46
 
47
+ #define THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(lhs, rhs, message) \
48
+ CHECK_OP_AND_THROW_ERROR_IF_NOT_TRUE_NO_RETURN(!=, lhs, rhs, message)
49
+
50
+ #define THROW_ERROR_IF_EQUAL_NO_RETURN(lhs, rhs, message) \
51
+ CHECK_OP_AND_THROW_ERROR_IF_NOT_TRUE_NO_RETURN(==, lhs, rhs, message)
52
+
37
53
  #define PACKAGE_NAME "rclnodejs"
38
54
 
39
55
  #ifdef DEBUG_ON
@@ -75,12 +75,13 @@ Napi::Value ActionCreateClient(const Napi::CallbackInfo& info) {
75
75
  &action_client_ops),
76
76
  RCL_RET_OK, rcl_get_error_string().str);
77
77
  auto js_obj = RclHandle::NewInstance(
78
- env, action_client, node_handle, [node](void* ptr) {
78
+ env, action_client, node_handle, [node, env](void* ptr) {
79
79
  rcl_action_client_t* action_client =
80
80
  reinterpret_cast<rcl_action_client_t*>(ptr);
81
81
  rcl_ret_t ret = rcl_action_client_fini(action_client, node);
82
82
  free(ptr);
83
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
83
+ THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
84
+ rcl_get_error_string().str);
84
85
  });
85
86
 
86
87
  return js_obj;
@@ -49,12 +49,13 @@ Napi::Value ActionAcceptNewGoal(const Napi::CallbackInfo& info) {
49
49
  malloc(sizeof(rcl_action_goal_handle_t)));
50
50
  *goal_handle = *new_goal;
51
51
  auto js_obj =
52
- RclHandle::NewInstance(env, goal_handle, nullptr, [](void* ptr) {
52
+ RclHandle::NewInstance(env, goal_handle, nullptr, [env](void* ptr) {
53
53
  rcl_action_goal_handle_t* goal_handle =
54
54
  reinterpret_cast<rcl_action_goal_handle_t*>(ptr);
55
55
  rcl_ret_t ret = rcl_action_goal_handle_fini(goal_handle);
56
56
  free(ptr);
57
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
57
+ THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
58
+ rcl_get_error_string().str);
58
59
  });
59
60
 
60
61
  return js_obj;
@@ -81,12 +81,13 @@ Napi::Value ActionCreateServer(const Napi::CallbackInfo& info) {
81
81
  action_name.c_str(), &action_server_ops),
82
82
  RCL_RET_OK, rcl_get_error_string().str);
83
83
  auto js_obj = RclHandle::NewInstance(
84
- env, action_server, node_handle, [node](void* ptr) {
84
+ env, action_server, node_handle, [node, env](void* ptr) {
85
85
  rcl_action_server_t* action_server =
86
86
  reinterpret_cast<rcl_action_server_t*>(ptr);
87
87
  rcl_ret_t ret = rcl_action_server_fini(action_server, node);
88
88
  free(ptr);
89
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
89
+ THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
90
+ rcl_get_error_string().str);
90
91
  });
91
92
 
92
93
  return js_obj;
@@ -390,13 +391,14 @@ Napi::Value ActionProcessCancelRequest(const Napi::CallbackInfo& info) {
390
391
  }
391
392
 
392
393
  *response = cancel_response_ptr->msg;
393
- auto js_obj =
394
- RclHandle::NewInstance(env, cancel_response_ptr, nullptr, [](void* ptr) {
394
+ auto js_obj = RclHandle::NewInstance(
395
+ env, cancel_response_ptr, nullptr, [env](void* ptr) {
395
396
  rcl_action_cancel_response_t* cancel_response_ptr =
396
397
  reinterpret_cast<rcl_action_cancel_response_t*>(ptr);
397
398
  rcl_ret_t ret = rcl_action_cancel_response_fini(cancel_response_ptr);
398
399
  free(ptr);
399
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
400
+ THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
401
+ rcl_get_error_string().str);
400
402
  });
401
403
  return js_obj;
402
404
  }
@@ -53,12 +53,13 @@ Napi::Value CreateClient(const Napi::CallbackInfo& info) {
53
53
  rcl_client_init(client, node, ts, service_name.c_str(), &client_ops),
54
54
  RCL_RET_OK, rcl_get_error_string().str);
55
55
 
56
- auto js_obj =
57
- RclHandle::NewInstance(env, client, node_handle, [node](void* ptr) {
56
+ auto js_obj = RclHandle::NewInstance(
57
+ env, client, node_handle, [node, env](void* ptr) {
58
58
  rcl_client_t* client = reinterpret_cast<rcl_client_t*>(ptr);
59
59
  rcl_ret_t ret = rcl_client_fini(client, node);
60
60
  free(ptr);
61
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
61
+ THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
62
+ rcl_get_error_string().str);
62
63
  });
63
64
 
64
65
  return js_obj;