rclnodejs 1.8.2 → 1.9.0-alpha.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.
Files changed (112) hide show
  1. package/README.md +46 -37
  2. package/index.js +62 -23
  3. package/lib/action/client.js +67 -3
  4. package/lib/action/server.js +1 -3
  5. package/lib/distro.js +2 -1
  6. package/lib/lifecycle_publisher.js +2 -2
  7. package/lib/message_info.js +94 -0
  8. package/lib/node.js +90 -14
  9. package/lib/parameter.js +5 -9
  10. package/lib/parameter_event_handler.js +468 -0
  11. package/lib/parameter_watcher.js +12 -12
  12. package/lib/service.js +8 -4
  13. package/lib/subscription.js +38 -5
  14. package/lib/time_source.js +3 -20
  15. package/lib/timer.js +2 -1
  16. package/lib/wait_for_message.js +111 -0
  17. package/package.json +7 -4
  18. package/prebuilds/linux-arm64/humble-jammy-arm64-rclnodejs.node +0 -0
  19. package/prebuilds/linux-arm64/jazzy-noble-arm64-rclnodejs.node +0 -0
  20. package/prebuilds/linux-arm64/kilted-noble-arm64-rclnodejs.node +0 -0
  21. package/prebuilds/linux-x64/humble-jammy-x64-rclnodejs.node +0 -0
  22. package/prebuilds/linux-x64/jazzy-noble-x64-rclnodejs.node +0 -0
  23. package/prebuilds/linux-x64/kilted-noble-x64-rclnodejs.node +0 -0
  24. package/rosidl_gen/generate_worker.js +3 -13
  25. package/rosidl_gen/idl_generator.js +210 -0
  26. package/rosidl_gen/index.js +3 -12
  27. package/rosidl_gen/packages.js +1 -3
  28. package/rosidl_gen/primitive_types.js +2 -2
  29. package/rosidl_parser/idl_parser.py +437 -0
  30. package/rosidl_parser/parser.py +2 -4
  31. package/rosidl_parser/rosidl_parser.js +27 -0
  32. package/scripts/run_asan_test.sh +118 -0
  33. package/src/executor.cpp +37 -2
  34. package/src/executor.h +11 -0
  35. package/src/macros.h +2 -2
  36. package/src/rcl_action_client_bindings.cpp +88 -12
  37. package/src/rcl_action_server_bindings.cpp +24 -13
  38. package/src/rcl_client_bindings.cpp +13 -5
  39. package/src/rcl_context_bindings.cpp +10 -11
  40. package/src/rcl_graph_bindings.cpp +2 -2
  41. package/src/rcl_guard_condition_bindings.cpp +12 -3
  42. package/src/rcl_lifecycle_bindings.cpp +34 -15
  43. package/src/rcl_node_bindings.cpp +11 -4
  44. package/src/rcl_publisher_bindings.cpp +12 -3
  45. package/src/rcl_service_bindings.cpp +12 -3
  46. package/src/rcl_subscription_bindings.cpp +92 -21
  47. package/src/rcl_timer_bindings.cpp +24 -9
  48. package/src/rcl_type_description_service_bindings.cpp +9 -1
  49. package/src/rcl_utilities.cpp +2 -2
  50. package/tools/jsdoc/Makefile +5 -0
  51. package/tools/jsdoc/README.md +96 -0
  52. package/tools/jsdoc/build-index.js +610 -0
  53. package/tools/jsdoc/publish.js +854 -0
  54. package/tools/jsdoc/regenerate-published-docs.js +605 -0
  55. package/tools/jsdoc/static/fonts/OpenSans-Bold-webfont.eot +0 -0
  56. package/tools/jsdoc/static/fonts/OpenSans-Bold-webfont.svg +1830 -0
  57. package/tools/jsdoc/static/fonts/OpenSans-Bold-webfont.woff +0 -0
  58. package/tools/jsdoc/static/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
  59. package/tools/jsdoc/static/fonts/OpenSans-BoldItalic-webfont.svg +1830 -0
  60. package/tools/jsdoc/static/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
  61. package/tools/jsdoc/static/fonts/OpenSans-Italic-webfont.eot +0 -0
  62. package/tools/jsdoc/static/fonts/OpenSans-Italic-webfont.svg +1830 -0
  63. package/tools/jsdoc/static/fonts/OpenSans-Italic-webfont.woff +0 -0
  64. package/tools/jsdoc/static/fonts/OpenSans-Light-webfont.eot +0 -0
  65. package/tools/jsdoc/static/fonts/OpenSans-Light-webfont.svg +1831 -0
  66. package/tools/jsdoc/static/fonts/OpenSans-Light-webfont.woff +0 -0
  67. package/tools/jsdoc/static/fonts/OpenSans-LightItalic-webfont.eot +0 -0
  68. package/tools/jsdoc/static/fonts/OpenSans-LightItalic-webfont.svg +1835 -0
  69. package/tools/jsdoc/static/fonts/OpenSans-LightItalic-webfont.woff +0 -0
  70. package/tools/jsdoc/static/fonts/OpenSans-Regular-webfont.eot +0 -0
  71. package/tools/jsdoc/static/fonts/OpenSans-Regular-webfont.svg +1831 -0
  72. package/tools/jsdoc/static/fonts/OpenSans-Regular-webfont.woff +0 -0
  73. package/tools/jsdoc/static/scripts/linenumber.js +25 -0
  74. package/tools/jsdoc/static/scripts/prettify/Apache-License-2.0.txt +202 -0
  75. package/tools/jsdoc/static/scripts/prettify/lang-css.js +36 -0
  76. package/tools/jsdoc/static/scripts/prettify/prettify.js +738 -0
  77. package/tools/jsdoc/static/styles/jsdoc-default.css +1012 -0
  78. package/tools/jsdoc/static/styles/prettify-jsdoc.css +111 -0
  79. package/tools/jsdoc/static/styles/prettify-tomorrow.css +132 -0
  80. package/tools/jsdoc/tmpl/augments.tmpl +10 -0
  81. package/tools/jsdoc/tmpl/container.tmpl +193 -0
  82. package/tools/jsdoc/tmpl/details.tmpl +143 -0
  83. package/tools/jsdoc/tmpl/example.tmpl +2 -0
  84. package/tools/jsdoc/tmpl/examples.tmpl +13 -0
  85. package/tools/jsdoc/tmpl/exceptions.tmpl +17 -0
  86. package/tools/jsdoc/tmpl/layout.tmpl +83 -0
  87. package/tools/jsdoc/tmpl/mainpage.tmpl +163 -0
  88. package/tools/jsdoc/tmpl/members.tmpl +43 -0
  89. package/tools/jsdoc/tmpl/method.tmpl +124 -0
  90. package/tools/jsdoc/tmpl/params.tmpl +133 -0
  91. package/tools/jsdoc/tmpl/properties.tmpl +110 -0
  92. package/tools/jsdoc/tmpl/returns.tmpl +12 -0
  93. package/tools/jsdoc/tmpl/source.tmpl +8 -0
  94. package/tools/jsdoc/tmpl/tutorial.tmpl +19 -0
  95. package/tools/jsdoc/tmpl/type.tmpl +7 -0
  96. package/types/action_client.d.ts +8 -0
  97. package/types/index.d.ts +34 -0
  98. package/types/message_info.d.ts +72 -0
  99. package/types/node.d.ts +21 -0
  100. package/types/parameter_event_handler.d.ts +139 -0
  101. package/types/subscription.d.ts +14 -2
  102. package/rosidl_convertor/README.md +0 -298
  103. package/rosidl_convertor/idl_convertor.js +0 -50
  104. package/rosidl_convertor/idl_convertor.py +0 -1250
  105. package/test_data_integrity.js +0 -108
  106. package/test_repro_exact.js +0 -57
  107. package/test_repro_hz.js +0 -86
  108. package/test_repro_pub.js +0 -36
  109. package/test_repro_stress.js +0 -83
  110. package/test_repro_sub.js +0 -64
  111. package/test_xproc_data.js +0 -64
  112. package/types/interfaces.d.ts +0 -8895
package/src/executor.cpp CHANGED
@@ -48,7 +48,8 @@ Executor::Executor(Napi::Env env, HandleManager* handle_manager,
48
48
  handle_manager_(handle_manager),
49
49
  delegate_(delegate),
50
50
  context_(nullptr),
51
- env_(env) {
51
+ env_(env),
52
+ work_pending_(false) {
52
53
  running_.store(false);
53
54
  }
54
55
 
@@ -105,17 +106,20 @@ void Executor::Stop() {
105
106
  // Stop thread first, and then uv_close
106
107
  // Make sure async_ is not used anymore
107
108
  running_.store(false);
109
+ // Wake the background thread in case it is waiting on the condvar.
110
+ work_done_cv_.notify_all();
108
111
  handle_manager_->StopWaitingHandles();
109
112
  uv_thread_join(&background_thread_);
110
113
 
111
114
  if (uv_is_active(reinterpret_cast<uv_handle_t*>(async_))) {
112
115
  static bool handle_closed = false;
116
+ handle_closed = false;
113
117
  uv_close(reinterpret_cast<uv_handle_t*>(async_),
114
118
  [](uv_handle_t* async) -> void {
115
119
  // Important Notice:
116
120
  // This might be called after Executor::~Executor()
117
121
  // Don't free Executor::async_ in Executor's dtor
118
- delete async;
122
+ delete reinterpret_cast<uv_async_t*>(async);
119
123
  handle_closed = true;
120
124
  });
121
125
  while (!handle_closed) uv_run(uv_default_loop(), UV_RUN_ONCE);
@@ -132,6 +136,21 @@ bool Executor::IsMainThread() {
132
136
 
133
137
  void Executor::DoWork(uv_async_t* handle) {
134
138
  Executor* executor = reinterpret_cast<Executor*>(handle->data);
139
+
140
+ // RAII guard: always clear work_pending_ and notify the background thread,
141
+ // even if ExecuteReadyHandles() throws (e.g. from N-API callbacks).
142
+ // Without this, the background thread would block forever on work_done_cv_.
143
+ struct WorkDoneGuard {
144
+ Executor* exec;
145
+ ~WorkDoneGuard() {
146
+ {
147
+ std::lock_guard<std::mutex> lock(exec->work_done_mutex_);
148
+ exec->work_pending_ = false;
149
+ }
150
+ exec->work_done_cv_.notify_one();
151
+ }
152
+ } guard{executor};
153
+
135
154
  executor->ExecuteReadyHandles();
136
155
  }
137
156
 
@@ -158,7 +177,23 @@ void Executor::Run(void* arg) {
158
177
 
159
178
  if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(executor->async_)) &&
160
179
  handle_manager->ready_handles_count() > 0) {
180
+ // Tell the main thread there is work to do, then wait for it to
181
+ // finish before re-entering rcl_wait. This prevents a data race
182
+ // where the background thread holds subscriptions in the wait set
183
+ // while the main thread modifies their state (e.g. content filter).
184
+ {
185
+ std::lock_guard<std::mutex> lock(executor->work_done_mutex_);
186
+ executor->work_pending_ = true;
187
+ }
161
188
  uv_async_send(executor->async_);
189
+
190
+ // Wait until DoWork() signals completion.
191
+ {
192
+ std::unique_lock<std::mutex> lock(executor->work_done_mutex_);
193
+ executor->work_done_cv_.wait(lock, [executor] {
194
+ return !executor->work_pending_ || !executor->running_.load();
195
+ });
196
+ }
162
197
  }
163
198
  }
164
199
 
package/src/executor.h CHANGED
@@ -20,7 +20,9 @@
20
20
  #include <uv.h>
21
21
 
22
22
  #include <atomic>
23
+ #include <condition_variable>
23
24
  #include <exception>
25
+ #include <mutex>
24
26
  #include <vector>
25
27
 
26
28
  #include "rcl_handle.h"
@@ -72,6 +74,15 @@ class Executor {
72
74
  Napi::Env env_;
73
75
 
74
76
  std::atomic_bool running_;
77
+
78
+ // Synchronization: the background thread waits after uv_async_send until
79
+ // the main thread finishes ExecuteReadyHandles. This prevents the
80
+ // background thread from re-entering rcl_wait (which holds a reference to
81
+ // subscriptions) while the main thread modifies subscription state (e.g.
82
+ // content filter changes).
83
+ std::mutex work_done_mutex_;
84
+ std::condition_variable work_done_cv_;
85
+ bool work_pending_; // true while the main thread is processing handles
75
86
  };
76
87
 
77
88
  } // namespace rclnodejs
package/src/macros.h CHANGED
@@ -22,8 +22,8 @@
22
22
  #define CHECK_OP_AND_THROW_ERROR_IF_NOT_TRUE(op, lhs, rhs, message) \
23
23
  { \
24
24
  if (lhs op rhs) { \
25
- rcl_reset_error(); \
26
25
  Napi::Error::New(env, message).ThrowAsJavaScriptException(); \
26
+ rcl_reset_error(); \
27
27
  return env.Undefined(); \
28
28
  } \
29
29
  }
@@ -31,8 +31,8 @@
31
31
  #define CHECK_OP_AND_THROW_ERROR_IF_NOT_TRUE_NO_RETURN(op, lhs, rhs, message) \
32
32
  { \
33
33
  if (lhs op rhs) { \
34
- rcl_reset_error(); \
35
34
  Napi::Error::New(env, message).ThrowAsJavaScriptException(); \
35
+ rcl_reset_error(); \
36
36
  } \
37
37
  }
38
38
 
@@ -70,10 +70,17 @@ Napi::Value ActionCreateClient(const Napi::CallbackInfo& info) {
70
70
  malloc(sizeof(rcl_action_client_t)));
71
71
  *action_client = rcl_action_get_zero_initialized_client();
72
72
 
73
- THROW_ERROR_IF_NOT_EQUAL(
74
- rcl_action_client_init(action_client, node, ts, action_name.c_str(),
75
- &action_client_ops),
76
- RCL_RET_OK, rcl_get_error_string().str);
73
+ {
74
+ rcl_ret_t ret = rcl_action_client_init(
75
+ action_client, node, ts, action_name.c_str(), &action_client_ops);
76
+ if (RCL_RET_OK != ret) {
77
+ std::string error_msg = rcl_get_error_string().str;
78
+ rcl_reset_error();
79
+ free(action_client);
80
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
81
+ return env.Undefined();
82
+ }
83
+ }
77
84
  auto js_obj = RclHandle::NewInstance(
78
85
  env, action_client, node_handle, [node, env](void* ptr) {
79
86
  rcl_action_client_t* action_client =
@@ -125,7 +132,7 @@ Napi::Value ActionSendGoalRequest(const Napi::CallbackInfo& info) {
125
132
  rcl_action_send_goal_request(action_client, buffer, &sequence_number),
126
133
  RCL_RET_OK, rcl_get_error_string().str);
127
134
 
128
- return Napi::Number::New(env, static_cast<int32_t>(sequence_number));
135
+ return Napi::Number::New(env, static_cast<double>(sequence_number));
129
136
  }
130
137
 
131
138
  Napi::Value ActionSendResultRequest(const Napi::CallbackInfo& info) {
@@ -142,7 +149,7 @@ Napi::Value ActionSendResultRequest(const Napi::CallbackInfo& info) {
142
149
  rcl_action_send_result_request(action_client, buffer, &sequence_number),
143
150
  RCL_RET_OK, rcl_get_error_string().str);
144
151
 
145
- return Napi::Number::New(env, static_cast<int32_t>(sequence_number));
152
+ return Napi::Number::New(env, static_cast<double>(sequence_number));
146
153
  }
147
154
 
148
155
  Napi::Value ActionTakeFeedback(const Napi::CallbackInfo& info) {
@@ -156,9 +163,9 @@ Napi::Value ActionTakeFeedback(const Napi::CallbackInfo& info) {
156
163
 
157
164
  rcl_ret_t ret = rcl_action_take_feedback(action_client, buffer);
158
165
  if (ret != RCL_RET_OK && ret != RCL_RET_ACTION_CLIENT_TAKE_FAILED) {
159
- Napi::Error::New(env, rcl_get_error_string().str)
160
- .ThrowAsJavaScriptException();
166
+ std::string error_msg = rcl_get_error_string().str;
161
167
  rcl_reset_error();
168
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
162
169
  return Napi::Boolean::New(env, false);
163
170
  }
164
171
 
@@ -179,9 +186,9 @@ Napi::Value ActionTakeStatus(const Napi::CallbackInfo& info) {
179
186
 
180
187
  rcl_ret_t ret = rcl_action_take_status(action_client, buffer);
181
188
  if (ret != RCL_RET_OK && ret != RCL_RET_ACTION_CLIENT_TAKE_FAILED) {
189
+ std::string error_msg = rcl_get_error_string().str;
182
190
  rcl_reset_error();
183
- Napi::Error::New(env, rcl_get_error_string().str)
184
- .ThrowAsJavaScriptException();
191
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
185
192
  return Napi::Boolean::New(env, false);
186
193
  }
187
194
 
@@ -240,8 +247,69 @@ Napi::Value ActionSendCancelRequest(const Napi::CallbackInfo& info) {
240
247
  rcl_action_send_cancel_request(action_client, buffer, &sequence_number),
241
248
  RCL_RET_OK, rcl_get_error_string().str);
242
249
 
243
- return Napi::Number::New(env, static_cast<int32_t>(sequence_number));
250
+ return Napi::Number::New(env, static_cast<double>(sequence_number));
251
+ }
252
+
253
+ #if ROS_VERSION >= 5000 // ROS2 Rolling
254
+ Napi::Value ActionConfigureFeedbackSubFilterAddGoalId(
255
+ const Napi::CallbackInfo& info) {
256
+ Napi::Env env = info.Env();
257
+
258
+ RclHandle* action_client_handle =
259
+ RclHandle::Unwrap(info[0].As<Napi::Object>());
260
+ rcl_action_client_t* action_client =
261
+ reinterpret_cast<rcl_action_client_t*>(action_client_handle->ptr());
262
+
263
+ auto goal_id_buffer = info[1].As<Napi::Buffer<uint8_t>>();
264
+ const uint8_t* goal_id_array = goal_id_buffer.Data();
265
+ size_t goal_id_size = goal_id_buffer.Length();
266
+
267
+ rcl_ret_t ret =
268
+ rcl_action_client_configure_feedback_subscription_filter_add_goal_id(
269
+ action_client, goal_id_array, goal_id_size);
270
+
271
+ if (RCL_RET_OK != ret) {
272
+ std::string error_text{
273
+ "Failed to add goal id to feedback subscription content filter: "};
274
+ error_text += rcl_get_error_string().str;
275
+ rcl_reset_error();
276
+ Napi::Error::New(env, error_text).ThrowAsJavaScriptException();
277
+ return Napi::Boolean::New(env, false);
278
+ }
279
+
280
+ return Napi::Boolean::New(env, true);
281
+ }
282
+
283
+ Napi::Value ActionConfigureFeedbackSubFilterRemoveGoalId(
284
+ const Napi::CallbackInfo& info) {
285
+ Napi::Env env = info.Env();
286
+
287
+ RclHandle* action_client_handle =
288
+ RclHandle::Unwrap(info[0].As<Napi::Object>());
289
+ rcl_action_client_t* action_client =
290
+ reinterpret_cast<rcl_action_client_t*>(action_client_handle->ptr());
291
+
292
+ auto goal_id_buffer = info[1].As<Napi::Buffer<uint8_t>>();
293
+ const uint8_t* goal_id_array = goal_id_buffer.Data();
294
+ size_t goal_id_size = goal_id_buffer.Length();
295
+
296
+ rcl_ret_t ret =
297
+ rcl_action_client_configure_feedback_subscription_filter_remove_goal_id(
298
+ action_client, goal_id_array, goal_id_size);
299
+
300
+ if (RCL_RET_OK != ret) {
301
+ std::string error_text{
302
+ "Failed to remove goal id from feedback subscription content "
303
+ "filter: "};
304
+ error_text += rcl_get_error_string().str;
305
+ rcl_reset_error();
306
+ Napi::Error::New(env, error_text).ThrowAsJavaScriptException();
307
+ return Napi::Boolean::New(env, false);
308
+ }
309
+
310
+ return Napi::Boolean::New(env, true);
244
311
  }
312
+ #endif // ROS_VERSION >= 5000
245
313
 
246
314
  #if ROS_VERSION >= 2505 // ROS2 >= Kilted
247
315
  Napi::Value ConfigureActionClientIntrospection(const Napi::CallbackInfo& info) {
@@ -300,7 +368,15 @@ Napi::Object InitActionClientBindings(Napi::Env env, Napi::Object exports) {
300
368
  #if ROS_VERSION >= 2505 // ROS2 >= Kilted
301
369
  exports.Set("configureActionClientIntrospection",
302
370
  Napi::Function::New(env, ConfigureActionClientIntrospection));
303
- #endif // ROS_VERSION >= 2505
371
+ #endif // ROS_VERSION >= 2505
372
+ #if ROS_VERSION >= 5000 // ROS2 Rolling
373
+ exports.Set(
374
+ "actionConfigureFeedbackSubFilterAddGoalId",
375
+ Napi::Function::New(env, ActionConfigureFeedbackSubFilterAddGoalId));
376
+ exports.Set(
377
+ "actionConfigureFeedbackSubFilterRemoveGoalId",
378
+ Napi::Function::New(env, ActionConfigureFeedbackSubFilterRemoveGoalId));
379
+ #endif // ROS_VERSION >= 5000
304
380
  return exports;
305
381
  }
306
382
 
@@ -76,10 +76,18 @@ Napi::Value ActionCreateServer(const Napi::CallbackInfo& info) {
76
76
  malloc(sizeof(rcl_action_server_t)));
77
77
  *action_server = rcl_action_get_zero_initialized_server();
78
78
 
79
- THROW_ERROR_IF_NOT_EQUAL(
80
- rcl_action_server_init(action_server, node, clock, ts,
81
- action_name.c_str(), &action_server_ops),
82
- RCL_RET_OK, rcl_get_error_string().str);
79
+ {
80
+ rcl_ret_t ret =
81
+ rcl_action_server_init(action_server, node, clock, ts,
82
+ action_name.c_str(), &action_server_ops);
83
+ if (RCL_RET_OK != ret) {
84
+ std::string error_msg = rcl_get_error_string().str;
85
+ rcl_reset_error();
86
+ free(action_server);
87
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
88
+ return env.Undefined();
89
+ }
90
+ }
83
91
  auto js_obj = RclHandle::NewInstance(
84
92
  env, action_server, node_handle, [node, env](void* ptr) {
85
93
  rcl_action_server_t* action_server =
@@ -118,6 +126,7 @@ Napi::Value ActionTakeResultRequest(const Napi::CallbackInfo& info) {
118
126
  return js_obj;
119
127
  }
120
128
 
129
+ free(header);
121
130
  return env.Undefined();
122
131
  }
123
132
 
@@ -140,6 +149,7 @@ Napi::Value ActionTakeGoalRequest(const Napi::CallbackInfo& info) {
140
149
  return js_obj;
141
150
  }
142
151
 
152
+ free(header);
143
153
  return env.Undefined();
144
154
  }
145
155
 
@@ -213,14 +223,14 @@ Napi::Value ActionTakeGoalResponse(const Napi::CallbackInfo& info) {
213
223
  free(header);
214
224
 
215
225
  if (ret != RCL_RET_OK && ret != RCL_RET_ACTION_CLIENT_TAKE_FAILED) {
226
+ std::string error_msg = rcl_get_error_string().str;
216
227
  rcl_reset_error();
217
- Napi::Error::New(env, rcl_get_error_string().str)
218
- .ThrowAsJavaScriptException();
228
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
219
229
  return env.Undefined();
220
230
  }
221
231
 
222
232
  if (ret != RCL_RET_ACTION_CLIENT_TAKE_FAILED) {
223
- return Napi::Number::New(env, static_cast<int32_t>(sequence_number));
233
+ return Napi::Number::New(env, static_cast<double>(sequence_number));
224
234
  }
225
235
  return env.Undefined();
226
236
  }
@@ -242,14 +252,14 @@ Napi::Value ActionTakeCancelResponse(const Napi::CallbackInfo& info) {
242
252
  free(header);
243
253
 
244
254
  if (ret != RCL_RET_OK && ret != RCL_RET_ACTION_CLIENT_TAKE_FAILED) {
255
+ std::string error_msg = rcl_get_error_string().str;
245
256
  rcl_reset_error();
246
- Napi::Error::New(env, rcl_get_error_string().str)
247
- .ThrowAsJavaScriptException();
257
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
248
258
  return env.Undefined();
249
259
  }
250
260
 
251
261
  if (ret != RCL_RET_ACTION_CLIENT_TAKE_FAILED) {
252
- return Napi::Number::New(env, static_cast<int32_t>(sequence_number));
262
+ return Napi::Number::New(env, static_cast<double>(sequence_number));
253
263
  }
254
264
  return env.Undefined();
255
265
  }
@@ -271,14 +281,14 @@ Napi::Value ActionTakeResultResponse(const Napi::CallbackInfo& info) {
271
281
  free(header);
272
282
 
273
283
  if (ret != RCL_RET_OK && ret != RCL_RET_ACTION_CLIENT_TAKE_FAILED) {
284
+ std::string error_msg = rcl_get_error_string().str;
274
285
  rcl_reset_error();
275
- Napi::Error::New(env, rcl_get_error_string().str)
276
- .ThrowAsJavaScriptException();
286
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
277
287
  return env.Undefined();
278
288
  }
279
289
 
280
290
  if (ret != RCL_RET_ACTION_CLIENT_TAKE_FAILED) {
281
- return Napi::Number::New(env, static_cast<int32_t>(sequence_number));
291
+ return Napi::Number::New(env, static_cast<double>(sequence_number));
282
292
  }
283
293
  return env.Undefined();
284
294
  }
@@ -455,6 +465,7 @@ Napi::Value ActionTakeCancelRequest(const Napi::CallbackInfo& info) {
455
465
  return js_obj;
456
466
  }
457
467
 
468
+ free(header);
458
469
  return env.Undefined();
459
470
  }
460
471
 
@@ -49,9 +49,17 @@ Napi::Value CreateClient(const Napi::CallbackInfo& info) {
49
49
  client_ops.qos = *qos_profile;
50
50
  }
51
51
 
52
- THROW_ERROR_IF_NOT_EQUAL(
53
- rcl_client_init(client, node, ts, service_name.c_str(), &client_ops),
54
- RCL_RET_OK, rcl_get_error_string().str);
52
+ {
53
+ rcl_ret_t ret =
54
+ rcl_client_init(client, node, ts, service_name.c_str(), &client_ops);
55
+ if (RCL_RET_OK != ret) {
56
+ std::string error_msg = rcl_get_error_string().str;
57
+ rcl_reset_error();
58
+ free(client);
59
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
60
+ return env.Undefined();
61
+ }
62
+ }
55
63
 
56
64
  auto js_obj = RclHandle::NewInstance(
57
65
  env, client, node_handle, [node, env](void* ptr) {
@@ -80,7 +88,7 @@ Napi::Value SendRequest(const Napi::CallbackInfo& info) {
80
88
  THROW_ERROR_IF_NOT_EQUAL(rcl_send_request(client, buffer, &sequence_number),
81
89
  RCL_RET_OK, rcl_get_error_string().str);
82
90
 
83
- return Napi::Number::New(env, static_cast<uint32_t>(sequence_number));
91
+ return Napi::Number::New(env, static_cast<double>(sequence_number));
84
92
  }
85
93
 
86
94
  Napi::Value RclTakeResponse(const Napi::CallbackInfo& info) {
@@ -96,7 +104,7 @@ Napi::Value RclTakeResponse(const Napi::CallbackInfo& info) {
96
104
  int64_t sequence_number = header.request_id.sequence_number;
97
105
 
98
106
  if (ret == RCL_RET_OK) {
99
- return Napi::Number::New(env, static_cast<uint32_t>(sequence_number));
107
+ return Napi::Number::New(env, static_cast<double>(sequence_number));
100
108
  }
101
109
 
102
110
  rcl_reset_error();
@@ -17,10 +17,10 @@
17
17
  #include <rcl/logging.h>
18
18
  #include <rcl/rcl.h>
19
19
 
20
- #include <rcpputils/scope_exit.hpp>
21
- // NOLINTNEXTLINE
22
20
  #include <string>
23
21
 
22
+ #include <rcpputils/scope_exit.hpp>
23
+
24
24
  #include "macros.h"
25
25
  #include "rcl_handle.h"
26
26
  #include "rcl_utilities.h"
@@ -54,6 +54,7 @@ Napi::Value Init(const Napi::CallbackInfo& info) {
54
54
  Napi::Array jsArgv = info[1].As<Napi::Array>();
55
55
  size_t argc = jsArgv.Length();
56
56
  char** argv = AbstractArgsFromNapiArray(jsArgv);
57
+ RCPPUTILS_SCOPE_EXIT({ FreeArgs(argv, argc); });
57
58
 
58
59
  // Set up the domain id.
59
60
  size_t domain_id = RCL_DEFAULT_DOMAIN_ID;
@@ -82,7 +83,6 @@ Napi::Value Init(const Napi::CallbackInfo& info) {
82
83
  RCL_RET_OK, rcl_logging_configure(&context->global_arguments, &allocator),
83
84
  rcl_get_error_string().str);
84
85
 
85
- RCPPUTILS_SCOPE_EXIT({ FreeArgs(argv, argc); });
86
86
  return env.Undefined();
87
87
  }
88
88
 
@@ -120,14 +120,13 @@ Napi::Value CreateContext(const Napi::CallbackInfo& info) {
120
120
  rcl_context_t* context =
121
121
  reinterpret_cast<rcl_context_t*>(malloc(sizeof(rcl_context_t)));
122
122
  *context = rcl_get_zero_initialized_context();
123
- auto js_obj =
124
- RclHandle::NewInstance(env, context, nullptr, [&env](void* ptr) {
125
- rcl_context_t* context = reinterpret_cast<rcl_context_t*>(ptr);
126
- rcl_ret_t ret = DestroyContext(env, context);
127
- free(ptr);
128
- THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
129
- rcl_get_error_string().str);
130
- });
123
+ auto js_obj = RclHandle::NewInstance(env, context, nullptr, [env](void* ptr) {
124
+ rcl_context_t* context = reinterpret_cast<rcl_context_t*>(ptr);
125
+ rcl_ret_t ret = DestroyContext(env, context);
126
+ free(ptr);
127
+ THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
128
+ rcl_get_error_string().str);
129
+ });
131
130
 
132
131
  return js_obj;
133
132
  }
@@ -18,10 +18,10 @@
18
18
  #include <rcl/graph.h>
19
19
  #include <rcl/rcl.h>
20
20
 
21
- #include <rcpputils/scope_exit.hpp>
22
- // NOLINTNEXTLINE
23
21
  #include <string>
24
22
 
23
+ #include <rcpputils/scope_exit.hpp>
24
+
25
25
  #include "macros.h"
26
26
  #include "rcl_handle.h"
27
27
  #include "rcl_utilities.h"
@@ -17,6 +17,8 @@
17
17
  #include <rcl/error_handling.h>
18
18
  #include <rcl/rcl.h>
19
19
 
20
+ #include <string>
21
+
20
22
  #include "macros.h"
21
23
  #include "rcl_handle.h"
22
24
  #include "rcl_utilities.h"
@@ -37,9 +39,16 @@ Napi::Value CreateGuardCondition(const Napi::CallbackInfo& info) {
37
39
  rcl_guard_condition_options_t gc_options =
38
40
  rcl_guard_condition_get_default_options();
39
41
 
40
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK,
41
- rcl_guard_condition_init(gc, context, gc_options),
42
- rcl_get_error_string().str);
42
+ {
43
+ rcl_ret_t ret = rcl_guard_condition_init(gc, context, gc_options);
44
+ if (RCL_RET_OK != ret) {
45
+ std::string error_msg = rcl_get_error_string().str;
46
+ rcl_reset_error();
47
+ free(gc);
48
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
49
+ return env.Undefined();
50
+ }
51
+ }
43
52
 
44
53
  auto handle = RclHandle::NewInstance(env, gc, nullptr, [env](void* ptr) {
45
54
  rcl_guard_condition_t* gc = reinterpret_cast<rcl_guard_condition_t*>(ptr);
@@ -79,11 +79,17 @@ Napi::Value CreateLifecycleStateMachine(const Napi::CallbackInfo& info) {
79
79
  RclHandle* clock_handle = RclHandle::Unwrap(info[2].As<Napi::Object>());
80
80
  rcl_clock_t* clock = reinterpret_cast<rcl_clock_t*>(clock_handle->ptr());
81
81
 
82
- THROW_ERROR_IF_NOT_EQUAL(
83
- RCL_RET_OK,
84
- rcl_lifecycle_state_machine_init(state_machine, node, clock, pn, cs, gs,
85
- gas, gat, gtg, &options),
86
- rcl_get_error_string().str);
82
+ {
83
+ rcl_ret_t ret = rcl_lifecycle_state_machine_init(
84
+ state_machine, node, clock, pn, cs, gs, gas, gat, gtg, &options);
85
+ if (RCL_RET_OK != ret) {
86
+ std::string error_msg = rcl_get_error_string().str;
87
+ rcl_reset_error();
88
+ free(state_machine);
89
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
90
+ return env.Undefined();
91
+ }
92
+ }
87
93
 
88
94
  auto js_obj = RclHandle::NewInstance(
89
95
  env, state_machine, node_handle, [node, env](void* ptr) {
@@ -99,11 +105,17 @@ Napi::Value CreateLifecycleStateMachine(const Napi::CallbackInfo& info) {
99
105
  rcl_lifecycle_get_default_state_machine_options();
100
106
  options.enable_com_interface = info[1].As<Napi::Boolean>().Value();
101
107
 
102
- THROW_ERROR_IF_NOT_EQUAL(
103
- RCL_RET_OK,
104
- rcl_lifecycle_state_machine_init(state_machine, node, pn, cs, gs, gas,
105
- gat, gtg, &options),
106
- rcl_get_error_string().str);
108
+ {
109
+ rcl_ret_t ret = rcl_lifecycle_state_machine_init(
110
+ state_machine, node, pn, cs, gs, gas, gat, gtg, &options);
111
+ if (RCL_RET_OK != ret) {
112
+ std::string error_msg = rcl_get_error_string().str;
113
+ rcl_reset_error();
114
+ free(state_machine);
115
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
116
+ return env.Undefined();
117
+ }
118
+ }
107
119
 
108
120
  auto js_obj = RclHandle::NewInstance(
109
121
  env, state_machine, node_handle, [node, env](void* ptr) {
@@ -118,11 +130,18 @@ Napi::Value CreateLifecycleStateMachine(const Napi::CallbackInfo& info) {
118
130
  const rcl_node_options_t* node_options =
119
131
  reinterpret_cast<const rcl_node_options_t*>(rcl_node_get_options(node));
120
132
 
121
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK,
122
- rcl_lifecycle_state_machine_init(
123
- state_machine, node, pn, cs, gs, gas, gat, gtg,
124
- true, &node_options->allocator),
125
- rcl_get_error_string().str);
133
+ {
134
+ rcl_ret_t ret = rcl_lifecycle_state_machine_init(
135
+ state_machine, node, pn, cs, gs, gas, gat, gtg, true,
136
+ &node_options->allocator);
137
+ if (RCL_RET_OK != ret) {
138
+ std::string error_msg = rcl_get_error_string().str;
139
+ rcl_reset_error();
140
+ free(state_machine);
141
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
142
+ return env.Undefined();
143
+ }
144
+ }
126
145
 
127
146
  auto js_obj = RclHandle::NewInstance(
128
147
  env, state_machine, node_handle, [node, node_options, env](void* ptr) {
@@ -224,10 +224,17 @@ Napi::Value CreateNode(const Napi::CallbackInfo& info) {
224
224
  options.rosout_qos = *qos_profile;
225
225
  }
226
226
 
227
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK,
228
- rcl_node_init(node, node_name.c_str(),
229
- name_space.c_str(), context, &options),
230
- rcl_get_error_string().str);
227
+ {
228
+ rcl_ret_t ret = rcl_node_init(node, node_name.c_str(), name_space.c_str(),
229
+ context, &options);
230
+ if (RCL_RET_OK != ret) {
231
+ std::string error_msg = rcl_get_error_string().str;
232
+ rcl_reset_error();
233
+ free(node);
234
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
235
+ return env.Undefined();
236
+ }
237
+ }
231
238
 
232
239
  auto handle = RclHandle::NewInstance(env, node, nullptr, [env](void* ptr) {
233
240
  rcl_node_t* node = reinterpret_cast<rcl_node_t*>(ptr);
@@ -51,9 +51,17 @@ Napi::Value CreatePublisher(const Napi::CallbackInfo& info) {
51
51
  publisher_ops.qos = *qos_profile;
52
52
  }
53
53
 
54
- THROW_ERROR_IF_NOT_EQUAL(
55
- rcl_publisher_init(publisher, node, ts, topic.c_str(), &publisher_ops),
56
- RCL_RET_OK, rcl_get_error_string().str);
54
+ {
55
+ rcl_ret_t ret = rcl_publisher_init(publisher, node, ts, topic.c_str(),
56
+ &publisher_ops);
57
+ if (RCL_RET_OK != ret) {
58
+ std::string error_msg = rcl_get_error_string().str;
59
+ rcl_reset_error();
60
+ free(publisher);
61
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
62
+ return env.Undefined();
63
+ }
64
+ }
57
65
 
58
66
  auto js_obj = RclHandle::NewInstance(
59
67
  env, publisher, node_handle, [node, env](void* ptr) {
@@ -66,6 +74,7 @@ Napi::Value CreatePublisher(const Napi::CallbackInfo& info) {
66
74
 
67
75
  return js_obj;
68
76
  } else {
77
+ free(publisher);
69
78
  Napi::Error::New(env, GetErrorMessageAndClear())
70
79
  .ThrowAsJavaScriptException();
71
80
  return env.Undefined();
@@ -52,9 +52,17 @@ Napi::Value CreateService(const Napi::CallbackInfo& info) {
52
52
  service_ops.qos = *qos_profile;
53
53
  }
54
54
 
55
- THROW_ERROR_IF_NOT_EQUAL(
56
- rcl_service_init(service, node, ts, service_name.c_str(), &service_ops),
57
- RCL_RET_OK, rcl_get_error_string().str);
55
+ {
56
+ rcl_ret_t ret = rcl_service_init(service, node, ts, service_name.c_str(),
57
+ &service_ops);
58
+ if (RCL_RET_OK != ret) {
59
+ std::string error_msg = rcl_get_error_string().str;
60
+ rcl_reset_error();
61
+ free(service);
62
+ Napi::Error::New(env, error_msg).ThrowAsJavaScriptException();
63
+ return env.Undefined();
64
+ }
65
+ }
58
66
  auto js_obj = RclHandle::NewInstance(
59
67
  env, service, node_handle, [node, env](void* ptr) {
60
68
  rcl_service_t* service = reinterpret_cast<rcl_service_t*>(ptr);
@@ -88,6 +96,7 @@ Napi::Value RclTakeRequest(const Napi::CallbackInfo& info) {
88
96
  return js_obj;
89
97
  }
90
98
 
99
+ free(header);
91
100
  return env.Undefined();
92
101
  }
93
102