rclnodejs 1.1.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.
Files changed (44) hide show
  1. package/README.md +4 -4
  2. package/binding.gyp +5 -0
  3. package/index.js +26 -3
  4. package/lib/context.js +4 -2
  5. package/lib/event_handler.js +474 -0
  6. package/lib/lifecycle.js +9 -0
  7. package/lib/lifecycle_publisher.js +2 -2
  8. package/lib/node.js +163 -28
  9. package/lib/publisher.js +31 -4
  10. package/lib/serialization.js +60 -0
  11. package/lib/subscription.js +48 -4
  12. package/lib/type_description_service.js +27 -1
  13. package/package.json +1 -1
  14. package/rosidl_gen/templates/message.dot +1 -1
  15. package/scripts/npmjs-readme.md +4 -4
  16. package/src/addon.cpp +4 -0
  17. package/src/executor.cpp +3 -4
  18. package/src/handle_manager.cpp +13 -2
  19. package/src/handle_manager.h +4 -1
  20. package/src/macros.h +17 -1
  21. package/src/rcl_action_client_bindings.cpp +3 -2
  22. package/src/rcl_action_goal_bindings.cpp +3 -2
  23. package/src/rcl_action_server_bindings.cpp +7 -5
  24. package/src/rcl_client_bindings.cpp +4 -3
  25. package/src/rcl_context_bindings.cpp +29 -19
  26. package/src/rcl_event_handle_bindings.cpp +294 -0
  27. package/src/rcl_event_handle_bindings.h +26 -0
  28. package/src/rcl_guard_condition_bindings.cpp +3 -2
  29. package/src/rcl_lifecycle_bindings.cpp +18 -4
  30. package/src/rcl_node_bindings.cpp +111 -3
  31. package/src/rcl_publisher_bindings.cpp +4 -3
  32. package/src/rcl_serialization_bindings.cpp +116 -0
  33. package/src/rcl_serialization_bindings.h +26 -0
  34. package/src/rcl_service_bindings.cpp +4 -3
  35. package/src/rcl_subscription_bindings.cpp +3 -2
  36. package/src/rcl_time_point_bindings.cpp +3 -2
  37. package/src/rcl_timer_bindings.cpp +8 -6
  38. package/src/rcl_utilities.cpp +31 -0
  39. package/src/rcl_utilities.h +7 -0
  40. package/tsconfig.json +2 -2
  41. package/types/context.d.ts +3 -2
  42. package/types/index.d.ts +26 -1
  43. package/types/lifecycle.d.ts +7 -0
  44. package/types/node.d.ts +60 -10
@@ -83,12 +83,13 @@ Napi::Value CreateLifecycleStateMachine(const Napi::CallbackInfo& info) {
83
83
  rcl_get_error_string().str);
84
84
 
85
85
  auto js_obj = RclHandle::NewInstance(
86
- env, state_machine, node_handle, [node](void* ptr) {
86
+ env, state_machine, node_handle, [node, env](void* ptr) {
87
87
  rcl_lifecycle_state_machine_t* state_machine =
88
88
  reinterpret_cast<rcl_lifecycle_state_machine_t*>(ptr);
89
89
  rcl_ret_t ret = rcl_lifecycle_state_machine_fini(state_machine, node);
90
90
  free(ptr);
91
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
91
+ THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
92
+ rcl_get_error_string().str);
92
93
  });
93
94
  #else
94
95
  const rcl_node_options_t* node_options =
@@ -101,13 +102,14 @@ Napi::Value CreateLifecycleStateMachine(const Napi::CallbackInfo& info) {
101
102
  rcl_get_error_string().str);
102
103
 
103
104
  auto js_obj = RclHandle::NewInstance(
104
- env, state_machine, node_handle, [node, node_options](void* ptr) {
105
+ env, state_machine, node_handle, [node, node_options, env](void* ptr) {
105
106
  rcl_lifecycle_state_machine_t* state_machine =
106
107
  reinterpret_cast<rcl_lifecycle_state_machine_t*>(ptr);
107
108
  rcl_ret_t ret = rcl_lifecycle_state_machine_fini(
108
109
  state_machine, node, &node_options->allocator);
109
110
  free(ptr);
110
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
111
+ THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
112
+ rcl_get_error_string().str);
111
113
  });
112
114
  #endif
113
115
 
@@ -372,6 +374,17 @@ Napi::Value IsInitialized(const Napi::CallbackInfo& info) {
372
374
  return Napi::Boolean::New(env, is_initialized);
373
375
  }
374
376
 
377
+ Napi::Value Print(const Napi::CallbackInfo& info) {
378
+ Napi::Env env = info.Env();
379
+ RclHandle* state_machine_handle =
380
+ RclHandle::Unwrap(info[0].As<Napi::Object>());
381
+ rcl_lifecycle_state_machine_t* state_machine =
382
+ reinterpret_cast<rcl_lifecycle_state_machine_t*>(
383
+ state_machine_handle->ptr());
384
+ rcl_print_state_machine(state_machine);
385
+ return env.Undefined();
386
+ }
387
+
375
388
  Napi::Object InitLifecycleBindings(Napi::Env env, Napi::Object exports) {
376
389
  exports.Set("createLifecycleStateMachine",
377
390
  Napi::Function::New(env, CreateLifecycleStateMachine));
@@ -396,6 +409,7 @@ Napi::Object InitLifecycleBindings(Napi::Env env, Napi::Object exports) {
396
409
  exports.Set("getLifecycleShutdownTransitionLabel",
397
410
  Napi::Function::New(env, GetLifecycleShutdownTransitionLabel));
398
411
  exports.Set("isInitialized", Napi::Function::New(env, IsInitialized));
412
+ exports.Set("print", Napi::Function::New(env, Print));
399
413
  return exports;
400
414
  }
401
415
 
@@ -20,10 +20,13 @@
20
20
  #include <rcl/arguments.h>
21
21
  #include <rcl/error_handling.h>
22
22
  #include <rcl/rcl.h>
23
+ #include <rcl/remap.h>
23
24
  #include <rcl_action/rcl_action.h>
24
25
  #include <rcl_yaml_param_parser/parser.h>
25
26
  #include <rcl_yaml_param_parser/types.h>
26
27
 
28
+ #include <rcpputils/scope_exit.hpp>
29
+ // NOLINTNEXTLINE
27
30
  #include <string>
28
31
 
29
32
  #include "macros.h"
@@ -180,21 +183,46 @@ Napi::Value CreateNode(const Napi::CallbackInfo& info) {
180
183
  rcl_context_t* context =
181
184
  reinterpret_cast<rcl_context_t*>(context_handle->ptr());
182
185
 
183
- rcl_node_t* node = reinterpret_cast<rcl_node_t*>(malloc(sizeof(rcl_node_t)));
186
+ Napi::Array jsArgv = info[3].As<Napi::Array>();
187
+ size_t argc = jsArgv.Length();
188
+ char** argv = AbstractArgsFromNapiArray(jsArgv);
189
+ RCPPUTILS_SCOPE_EXIT({ FreeArgs(argv, argc); });
190
+
191
+ rcl_arguments_t arguments = rcl_get_zero_initialized_arguments();
192
+ rcl_ret_t ret =
193
+ rcl_parse_arguments(argc, argv, rcl_get_default_allocator(), &arguments);
194
+ if ((ret != RCL_RET_OK) || HasUnparsedROSArgs(arguments)) {
195
+ Napi::Error::New(env, "failed to parse arguments")
196
+ .ThrowAsJavaScriptException();
197
+ return env.Undefined();
198
+ }
184
199
 
200
+ RCPPUTILS_SCOPE_EXIT({
201
+ if (RCL_RET_OK != rcl_arguments_fini(&arguments)) {
202
+ Napi::Error::New(env, "failed to fini arguments")
203
+ .ThrowAsJavaScriptException();
204
+ rcl_reset_error();
205
+ }
206
+ });
207
+ bool use_global_arguments = info[4].As<Napi::Boolean>().Value();
208
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(malloc(sizeof(rcl_node_t)));
185
209
  *node = rcl_get_zero_initialized_node();
210
+
186
211
  rcl_node_options_t options = rcl_node_get_default_options();
212
+ options.use_global_arguments = use_global_arguments;
213
+ options.arguments = arguments;
187
214
 
188
215
  THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK,
189
216
  rcl_node_init(node, node_name.c_str(),
190
217
  name_space.c_str(), context, &options),
191
218
  rcl_get_error_string().str);
192
219
 
193
- auto handle = RclHandle::NewInstance(env, node, nullptr, [](void* ptr) {
220
+ auto handle = RclHandle::NewInstance(env, node, nullptr, [env](void* ptr) {
194
221
  rcl_node_t* node = reinterpret_cast<rcl_node_t*>(ptr);
195
222
  rcl_ret_t ret = rcl_node_fini(node);
196
223
  free(ptr);
197
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
224
+ THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
225
+ rcl_get_error_string().str);
198
226
  });
199
227
 
200
228
  return handle;
@@ -446,6 +474,82 @@ Napi::Value GetFullyQualifiedName(const Napi::CallbackInfo& info) {
446
474
  return Napi::String::New(env, fully_qualified_node_name);
447
475
  }
448
476
 
477
+ Napi::Value GetRMWImplementationIdentifier(const Napi::CallbackInfo& info) {
478
+ return Napi::String::New(info.Env(), rmw_get_implementation_identifier());
479
+ }
480
+
481
+ Napi::Value ResolveName(const Napi::CallbackInfo& info) {
482
+ Napi::Env env = info.Env();
483
+
484
+ RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
485
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
486
+ const rcl_node_options_t* node_options = rcl_node_get_options(node);
487
+ std::string topic_name = info[1].As<Napi::String>().Utf8Value();
488
+ bool only_expand = info[2].As<Napi::Boolean>().Value();
489
+ bool is_service = info[3].As<Napi::Boolean>().Value();
490
+
491
+ char* output_cstr = nullptr;
492
+ rcl_ret_t ret =
493
+ rcl_node_resolve_name(node, topic_name.c_str(), node_options->allocator,
494
+ is_service, only_expand, &output_cstr);
495
+
496
+ auto name_deleter = [&]() {
497
+ node_options->allocator.deallocate(output_cstr,
498
+ node_options->allocator.state);
499
+ };
500
+
501
+ RCPPUTILS_SCOPE_EXIT({ name_deleter(); });
502
+
503
+ if (RCL_RET_OK != ret) {
504
+ Napi::Error::New(env, ("failed to resolve name"))
505
+ .ThrowAsJavaScriptException();
506
+ return env.Undefined();
507
+ }
508
+
509
+ return Napi::String::New(env, output_cstr);
510
+ }
511
+
512
+ Napi::Value RemapTopicName(const Napi::CallbackInfo& info) {
513
+ Napi::Env env = info.Env();
514
+ RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
515
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
516
+ std::string topic_name = info[1].As<Napi::String>().Utf8Value();
517
+
518
+ const rcl_node_options_t* node_options = rcl_node_get_options(node);
519
+ if (nullptr == node_options) {
520
+ Napi::Error::New(env, "failed to get node options")
521
+ .ThrowAsJavaScriptException();
522
+ return env.Undefined();
523
+ }
524
+
525
+ const rcl_arguments_t* global_args = nullptr;
526
+ if (node_options->use_global_arguments) {
527
+ global_args = &(node->context->global_arguments);
528
+ }
529
+
530
+ char* output_cstr = nullptr;
531
+ rcl_ret_t ret = rcl_remap_topic_name(
532
+ &(node_options->arguments), global_args, topic_name.c_str(),
533
+ rcl_node_get_name(node), rcl_node_get_namespace(node),
534
+ node_options->allocator, &output_cstr);
535
+ if (RCL_RET_OK != ret) {
536
+ Napi::Error::New(env, "failed to remap topic name")
537
+ .ThrowAsJavaScriptException();
538
+ return env.Undefined();
539
+ }
540
+ if (nullptr == output_cstr) {
541
+ return Napi::String::New(env, topic_name);
542
+ }
543
+
544
+ auto name_deleter = [&]() {
545
+ node_options->allocator.deallocate(output_cstr,
546
+ node_options->allocator.state);
547
+ };
548
+ RCPPUTILS_SCOPE_EXIT({ name_deleter(); });
549
+
550
+ return Napi::String::New(env, output_cstr);
551
+ }
552
+
449
553
  Napi::Object InitNodeBindings(Napi::Env env, Napi::Object exports) {
450
554
  exports.Set("getParameterOverrides",
451
555
  Napi::Function::New(env, GetParameterOverrides));
@@ -468,6 +572,10 @@ Napi::Object InitNodeBindings(Napi::Env env, Napi::Object exports) {
468
572
  exports.Set("getNodeNames", Napi::Function::New(env, GetNodeNames));
469
573
  exports.Set("getFullyQualifiedName",
470
574
  Napi::Function::New(env, GetFullyQualifiedName));
575
+ exports.Set("getRMWImplementationIdentifier",
576
+ Napi::Function::New(env, GetRMWImplementationIdentifier));
577
+ exports.Set("resolveName", Napi::Function::New(env, ResolveName));
578
+ exports.Set("remapTopicName", Napi::Function::New(env, RemapTopicName));
471
579
  return exports;
472
580
  }
473
581
 
@@ -55,12 +55,13 @@ Napi::Value CreatePublisher(const Napi::CallbackInfo& info) {
55
55
  rcl_publisher_init(publisher, node, ts, topic.c_str(), &publisher_ops),
56
56
  RCL_RET_OK, rcl_get_error_string().str);
57
57
 
58
- auto js_obj =
59
- RclHandle::NewInstance(env, publisher, node_handle, [node](void* ptr) {
58
+ auto js_obj = RclHandle::NewInstance(
59
+ env, publisher, node_handle, [node, env](void* ptr) {
60
60
  rcl_publisher_t* publisher = reinterpret_cast<rcl_publisher_t*>(ptr);
61
61
  rcl_ret_t ret = rcl_publisher_fini(publisher, node);
62
62
  free(ptr);
63
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
63
+ THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
64
+ rcl_get_error_string().str);
64
65
  });
65
66
 
66
67
  return js_obj;
@@ -0,0 +1,116 @@
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
+ #include "rcl_serialization_bindings.h"
16
+
17
+ #include <rmw/rmw.h>
18
+ #include <rmw/serialized_message.h>
19
+ #include <rosidl_runtime_c/message_type_support_struct.h>
20
+
21
+ #include <string>
22
+
23
+ #include "rcl_utilities.h"
24
+
25
+ namespace {
26
+
27
+ struct SerializedMessage {
28
+ explicit SerializedMessage(Napi::Env env, rcutils_allocator_t allocator)
29
+ : env(env) {
30
+ rcl_msg = rmw_get_zero_initialized_serialized_message();
31
+ rcutils_ret_t rcutils_ret =
32
+ rmw_serialized_message_init(&rcl_msg, 0u, &allocator);
33
+ if (RCUTILS_RET_OK != rcutils_ret) {
34
+ Napi::Error::New(env, "failed to initialize serialized message")
35
+ .ThrowAsJavaScriptException();
36
+ }
37
+ }
38
+
39
+ ~SerializedMessage() {
40
+ rcutils_ret_t ret = rmw_serialized_message_fini(&rcl_msg);
41
+ if (RCUTILS_RET_OK != ret) {
42
+ Napi::Error::New(env,
43
+ "failed to fini rcl_serialized_msg_t in destructor.")
44
+ .ThrowAsJavaScriptException();
45
+ rcutils_reset_error();
46
+ }
47
+ }
48
+
49
+ rcl_serialized_message_t rcl_msg;
50
+ Napi::Env env;
51
+ };
52
+
53
+ } // namespace
54
+
55
+ namespace rclnodejs {
56
+
57
+ Napi::Value Serialize(const Napi::CallbackInfo& info) {
58
+ Napi::Env env = info.Env();
59
+
60
+ std::string package_name = info[0].As<Napi::String>().Utf8Value();
61
+ std::string message_sub_folder = info[1].As<Napi::String>().Utf8Value();
62
+ std::string message_name = info[2].As<Napi::String>().Utf8Value();
63
+ void* ros_msg = info[3].As<Napi::Buffer<char>>().Data();
64
+ const rosidl_message_type_support_t* ts =
65
+ GetMessageTypeSupport(package_name, message_sub_folder, message_name);
66
+
67
+ // Create a serialized message object.
68
+ SerializedMessage serialized_msg(env, rcutils_get_default_allocator());
69
+
70
+ rmw_ret_t rmw_ret = rmw_serialize(ros_msg, ts, &serialized_msg.rcl_msg);
71
+ if (RMW_RET_OK != rmw_ret) {
72
+ Napi::Error::New(env, "Failed to serialize ROS message")
73
+ .ThrowAsJavaScriptException();
74
+ return env.Undefined();
75
+ }
76
+ Napi::Buffer<char> buffer = Napi::Buffer<char>::Copy(
77
+ env, reinterpret_cast<const char*>(serialized_msg.rcl_msg.buffer),
78
+ serialized_msg.rcl_msg.buffer_length);
79
+ return buffer;
80
+ }
81
+
82
+ Napi::Value Deserialize(const Napi::CallbackInfo& info) {
83
+ Napi::Env env = info.Env();
84
+
85
+ std::string package_name = info[0].As<Napi::String>().Utf8Value();
86
+ std::string message_sub_folder = info[1].As<Napi::String>().Utf8Value();
87
+ std::string message_name = info[2].As<Napi::String>().Utf8Value();
88
+ const rosidl_message_type_support_t* ts =
89
+ GetMessageTypeSupport(package_name, message_sub_folder, message_name);
90
+ Napi::Buffer<char> serialized = info[3].As<Napi::Buffer<char>>();
91
+ void* msg_taken = info[4].As<Napi::Buffer<char>>().Data();
92
+
93
+ // Create a serialized message object.
94
+ rcl_serialized_message_t serialized_msg =
95
+ rmw_get_zero_initialized_serialized_message();
96
+ serialized_msg.buffer_capacity = serialized.Length();
97
+ serialized_msg.buffer_length = serialized.Length();
98
+ serialized_msg.buffer = reinterpret_cast<uint8_t*>(serialized.Data());
99
+
100
+ rmw_ret_t rmw_ret = rmw_deserialize(&serialized_msg, ts, msg_taken);
101
+
102
+ if (RMW_RET_OK != rmw_ret) {
103
+ Napi::Error::New(env, "failed to deserialize ROS message")
104
+ .ThrowAsJavaScriptException();
105
+ }
106
+
107
+ return env.Undefined();
108
+ }
109
+
110
+ Napi::Object InitSerializationBindings(Napi::Env env, Napi::Object exports) {
111
+ exports.Set("serialize", Napi::Function::New(env, Serialize));
112
+ exports.Set("deserialize", Napi::Function::New(env, Deserialize));
113
+ return exports;
114
+ }
115
+
116
+ } // namespace rclnodejs
@@ -0,0 +1,26 @@
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
+ #ifndef SRC_RCL_SERIALIZATION_BINDINGS_H_
16
+ #define SRC_RCL_SERIALIZATION_BINDINGS_H_
17
+
18
+ #include <napi.h>
19
+
20
+ namespace rclnodejs {
21
+
22
+ Napi::Object InitSerializationBindings(Napi::Env env, Napi::Object exports);
23
+
24
+ }
25
+
26
+ #endif // SRC_RCL_SERIALIZATION_BINDINGS_H_
@@ -55,12 +55,13 @@ Napi::Value CreateService(const Napi::CallbackInfo& info) {
55
55
  THROW_ERROR_IF_NOT_EQUAL(
56
56
  rcl_service_init(service, node, ts, service_name.c_str(), &service_ops),
57
57
  RCL_RET_OK, rcl_get_error_string().str);
58
- auto js_obj =
59
- RclHandle::NewInstance(env, service, node_handle, [node](void* ptr) {
58
+ auto js_obj = RclHandle::NewInstance(
59
+ env, service, node_handle, [node, env](void* ptr) {
60
60
  rcl_service_t* service = reinterpret_cast<rcl_service_t*>(ptr);
61
61
  rcl_ret_t ret = rcl_service_fini(service, node);
62
62
  free(ptr);
63
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
63
+ THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
64
+ rcl_get_error_string().str);
64
65
  });
65
66
 
66
67
  return js_obj;
@@ -136,12 +136,13 @@ Napi::Value CreateSubscription(const Napi::CallbackInfo& info) {
136
136
  rcl_get_error_string().str);
137
137
 
138
138
  auto js_obj = RclHandle::NewInstance(
139
- env, subscription, node_handle, [node](void* ptr) {
139
+ env, subscription, node_handle, [node, env](void* ptr) {
140
140
  rcl_subscription_t* subscription =
141
141
  reinterpret_cast<rcl_subscription_t*>(ptr);
142
142
  rcl_ret_t ret = rcl_subscription_fini(subscription, node);
143
143
  free(ptr);
144
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
144
+ THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
145
+ rcl_get_error_string().str);
145
146
  });
146
147
 
147
148
  return js_obj;
@@ -151,11 +151,12 @@ Napi::Value CreateClock(const Napi::CallbackInfo& info) {
151
151
  rcl_clock_init(clock_type, clock, &allocator),
152
152
  rcl_get_error_string().str);
153
153
 
154
- return RclHandle::NewInstance(env, clock, nullptr, [](void* ptr) {
154
+ return RclHandle::NewInstance(env, clock, nullptr, [env](void* ptr) {
155
155
  rcl_clock_t* clock = reinterpret_cast<rcl_clock_t*>(ptr);
156
156
  rcl_ret_t ret = rcl_clock_fini(clock);
157
157
  free(ptr);
158
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
158
+ THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
159
+ rcl_get_error_string().str);
159
160
  });
160
161
  }
161
162
 
@@ -58,12 +58,14 @@ Napi::Value CreateTimer(const Napi::CallbackInfo& info) {
58
58
  rcl_get_error_string().str);
59
59
  #endif
60
60
 
61
- auto js_obj = RclHandle::NewInstance(env, timer, clock_handle, [](void* ptr) {
62
- rcl_timer_t* timer = reinterpret_cast<rcl_timer_t*>(ptr);
63
- rcl_ret_t ret = rcl_timer_fini(timer);
64
- free(ptr);
65
- THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
66
- });
61
+ auto js_obj =
62
+ RclHandle::NewInstance(env, timer, clock_handle, [env](void* ptr) {
63
+ rcl_timer_t* timer = reinterpret_cast<rcl_timer_t*>(ptr);
64
+ rcl_ret_t ret = rcl_timer_fini(timer);
65
+ free(ptr);
66
+ THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
67
+ rcl_get_error_string().str);
68
+ });
67
69
 
68
70
  return js_obj;
69
71
  }
@@ -19,6 +19,7 @@
19
19
  #include <rmw/topic_endpoint_info.h>
20
20
  #include <uv.h>
21
21
 
22
+ #include <cstdio>
22
23
  #include <memory>
23
24
  #include <string>
24
25
 
@@ -260,4 +261,34 @@ Napi::Array ConvertToJSTopicEndpointInfoList(
260
261
  return list;
261
262
  }
262
263
 
264
+ char** AbstractArgsFromNapiArray(const Napi::Array& jsArgv) {
265
+ size_t argc = jsArgv.Length();
266
+ char** argv = nullptr;
267
+
268
+ if (argc > 0) {
269
+ argv = reinterpret_cast<char**>(malloc(argc * sizeof(char*)));
270
+ for (size_t i = 0; i < argc; i++) {
271
+ std::string arg = jsArgv.Get(i).As<Napi::String>().Utf8Value();
272
+ int len = arg.length() + 1;
273
+ argv[i] = reinterpret_cast<char*>(malloc(len * sizeof(char)));
274
+ snprintf(argv[i], len, "%s", arg.c_str());
275
+ }
276
+ }
277
+ return argv;
278
+ }
279
+
280
+ void FreeArgs(char** argv, size_t argc) {
281
+ if (argv) {
282
+ for (size_t i = 0; i < argc; i++) {
283
+ free(argv[i]);
284
+ }
285
+ free(argv);
286
+ }
287
+ }
288
+
289
+ bool HasUnparsedROSArgs(const rcl_arguments_t& rcl_args) {
290
+ int unparsed_ros_args_count = rcl_arguments_get_count_unparsed_ros(&rcl_args);
291
+ return unparsed_ros_args_count != 0;
292
+ }
293
+
263
294
  } // namespace rclnodejs
@@ -53,6 +53,13 @@ Napi::Array ConvertToJSTopicEndpointInfoList(
53
53
 
54
54
  Napi::Value ConvertToQoS(Napi::Env env, const rmw_qos_profile_t* qos_profile);
55
55
 
56
+ // `AbstractArgsFromNapiArray` and `FreeArgs` must be called in pairs.
57
+ char** AbstractArgsFromNapiArray(const Napi::Array& jsArgv);
58
+ // `AbstractArgsFromNapiArray` and `FreeArgs` must be called in pairs.
59
+ void FreeArgs(char** argv, size_t argc);
60
+
61
+ bool HasUnparsedROSArgs(const rcl_arguments_t& rcl_args);
62
+
56
63
  } // namespace rclnodejs
57
64
 
58
65
  #endif // SRC_RCL_UTILITIES_H_
package/tsconfig.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "compilerOptions": {
3
3
  "module": "commonjs",
4
4
  "moduleResolution": "node",
5
- "target": "es6",
5
+ "target": "es2020",
6
6
  /* Strict Type-Checking Options */
7
7
  "strict": true,
8
8
  /* Additional Checks */
@@ -11,7 +11,7 @@
11
11
  "noUnusedParameters": true,
12
12
  "noImplicitReturns": true,
13
13
  "noFallthroughCasesInSwitch": true,
14
- "lib": ["es2017"]
14
+ "lib": ["es2020"]
15
15
  },
16
16
  "include": [
17
17
  "types/**/*"
@@ -38,8 +38,9 @@ declare module 'rclnodejs' {
38
38
  * Create a new instance in uninitialized state.
39
39
  * Call rcl.init(context) to initialize this context state for
40
40
  * use in creating nodes, etc.
41
+ * @param {bigint} - Optional, The domain ID of this context.
41
42
  */
42
- constructor();
43
+ constructor(domainId?: bigint);
43
44
 
44
45
  /**
45
46
  * Test if this context has not been initialized by rcl.init(context).
@@ -92,6 +93,6 @@ declare module 'rclnodejs' {
92
93
  * Get the domain ID of this context.
93
94
  * @returns domain ID of this context
94
95
  */
95
- domainId(): number;
96
+ domainId(): bigint;
96
97
  }
97
98
  }
package/types/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  /// <reference path="./base.d.ts" />
2
2
 
3
3
  declare module 'rclnodejs' {
4
+ type Class = new (...args: any[]) => any;
5
+
4
6
  /**
5
7
  * Create a node.
6
8
  *
@@ -11,6 +13,9 @@ declare module 'rclnodejs' {
11
13
  * @param namespace - The namespace used in ROS, default is an empty string.
12
14
  * @param context - The context, default is Context.defaultContext().
13
15
  * @param options - The node options, default is NodeOptions.defaultOptions.
16
+ * @param args - The arguments to be passed to the node, default is an empty array.
17
+ * @param useGlobalArguments - If true, the node will use global arguments, default is true.
18
+ * If false, the node will not use global arguments.
14
19
  * @returns The new Node instance.
15
20
  * @deprecated since 0.18.0, Use new Node constructor.
16
21
  */
@@ -18,7 +23,9 @@ declare module 'rclnodejs' {
18
23
  nodeName: string,
19
24
  namespace?: string,
20
25
  context?: Context,
21
- options?: NodeOptions
26
+ options?: NodeOptions,
27
+ args?: string[],
28
+ useGlobalArguments?: boolean
22
29
  ): Node;
23
30
 
24
31
  /**
@@ -182,4 +189,22 @@ declare module 'rclnodejs' {
182
189
  * @returns An array of the names and types.
183
190
  */
184
191
  function getActionNamesAndTypes(node: Node): NamesAndTypesQueryResult;
192
+
193
+ /**
194
+ * Serialize a message to a Buffer.
195
+ *
196
+ * @param message - The message to be serialized.
197
+ * @param typeClass - The type class of the message.
198
+ * @returns A Buffer containing the serialized message.
199
+ */
200
+ function serializeMessage(message: object, typeClass: Class): Buffer;
201
+
202
+ /**
203
+ * Deserialize a message from a Buffer.
204
+ *
205
+ * @param buffer - The Buffer containing the serialized message.
206
+ * @param typeClass - The type class of the message.
207
+ * @returns An Object representing the deserialized message.
208
+ */
209
+ function deserializeMessage(buffer: Buffer, typeClass: Class): object;
185
210
  }
@@ -333,6 +333,13 @@ declare module 'rclnodejs' {
333
333
  * @returns {boolean} true if the state machine is initialized; otherwise false.
334
334
  */
335
335
  get isInitialized(): boolean;
336
+
337
+ /**
338
+ * Log the state machine data.
339
+ *
340
+ * @returns {undefined} void.
341
+ */
342
+ print(): void;
336
343
  }
337
344
  } // lifecycle namespace
338
345
  } // rclnodejs namespace