rclnodejs 0.33.0 → 1.0.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 (66) hide show
  1. package/README.md +3 -3
  2. package/binding.gyp +17 -2
  3. package/lib/client.js +2 -3
  4. package/lib/context.js +8 -0
  5. package/lib/logging.js +26 -9
  6. package/lib/node.js +53 -0
  7. package/lib/publisher.js +8 -0
  8. package/lib/service.js +9 -2
  9. package/lib/subscription.js +8 -0
  10. package/lib/timer.js +32 -0
  11. package/package.json +4 -4
  12. package/scripts/config.js +1 -0
  13. package/scripts/npmjs-readme.md +3 -3
  14. package/src/addon.cpp +54 -53
  15. package/src/executor.cpp +19 -10
  16. package/src/{executor.hpp → executor.h} +7 -5
  17. package/src/handle_manager.cpp +30 -56
  18. package/src/{handle_manager.hpp → handle_manager.h} +8 -7
  19. package/src/{macros.hpp → macros.h} +7 -5
  20. package/src/rcl_action_client_bindings.cpp +231 -0
  21. package/src/{rcl_action_bindings.hpp → rcl_action_client_bindings.h} +6 -11
  22. package/src/rcl_action_goal_bindings.cpp +117 -0
  23. package/src/rcl_action_goal_bindings.h +26 -0
  24. package/src/rcl_action_server_bindings.cpp +470 -0
  25. package/src/rcl_action_server_bindings.h +26 -0
  26. package/src/rcl_bindings.cpp +42 -2010
  27. package/src/{rcl_bindings.hpp → rcl_bindings.h} +5 -25
  28. package/src/rcl_client_bindings.cpp +183 -0
  29. package/src/rcl_client_bindings.h +26 -0
  30. package/src/rcl_context_bindings.cpp +156 -0
  31. package/src/rcl_context_bindings.h +26 -0
  32. package/src/rcl_graph_bindings.cpp +280 -0
  33. package/src/rcl_graph_bindings.h +26 -0
  34. package/src/rcl_guard_condition_bindings.cpp +75 -0
  35. package/src/rcl_guard_condition_bindings.h +26 -0
  36. package/src/rcl_handle.cpp +41 -57
  37. package/src/{rcl_handle.hpp → rcl_handle.h} +18 -17
  38. package/src/rcl_lifecycle_bindings.cpp +135 -114
  39. package/src/{rcl_lifecycle_bindings.hpp → rcl_lifecycle_bindings.h} +5 -7
  40. package/src/rcl_logging_bindings.cpp +96 -0
  41. package/src/rcl_logging_bindings.h +26 -0
  42. package/src/rcl_names_bindings.cpp +255 -0
  43. package/src/rcl_names_bindings.h +26 -0
  44. package/src/rcl_node_bindings.cpp +447 -0
  45. package/src/rcl_node_bindings.h +26 -0
  46. package/src/rcl_publisher_bindings.cpp +141 -0
  47. package/src/rcl_publisher_bindings.h +26 -0
  48. package/src/rcl_service_bindings.cpp +185 -0
  49. package/src/rcl_service_bindings.h +26 -0
  50. package/src/rcl_subscription_bindings.cpp +335 -0
  51. package/src/rcl_subscription_bindings.h +26 -0
  52. package/src/rcl_time_point_bindings.cpp +194 -0
  53. package/src/rcl_time_point_bindings.h +26 -0
  54. package/src/rcl_timer_bindings.cpp +237 -0
  55. package/src/rcl_timer_bindings.h +26 -0
  56. package/src/rcl_utilities.cpp +166 -1
  57. package/src/{rcl_utilities.hpp → rcl_utilities.h} +21 -3
  58. package/src/shadow_node.cpp +56 -75
  59. package/src/{shadow_node.hpp → shadow_node.h} +18 -17
  60. package/types/context.d.ts +6 -0
  61. package/types/node.d.ts +37 -0
  62. package/types/publisher.d.ts +6 -0
  63. package/types/service.d.ts +6 -0
  64. package/types/subscription.d.ts +6 -0
  65. package/types/timer.d.ts +18 -0
  66. package/src/rcl_action_bindings.cpp +0 -826
@@ -0,0 +1,447 @@
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_NODE_BINDINGS_H_
16
+ #define SRC_RCL_NODE_BINDINGS_H_
17
+
18
+ #include "rcl_node_bindings.h"
19
+
20
+ #include <rcl/arguments.h>
21
+ #include <rcl/error_handling.h>
22
+ #include <rcl/rcl.h>
23
+ #include <rcl_action/rcl_action.h>
24
+ #include <rcl_yaml_param_parser/parser.h>
25
+ #include <rcl_yaml_param_parser/types.h>
26
+
27
+ #include <string>
28
+
29
+ #include "macros.h"
30
+ #include "rcl_handle.h"
31
+ #include "rcl_utilities.h"
32
+
33
+ namespace rclnodejs {
34
+
35
+ static const int PARAMETER_NOT_SET = 0;
36
+ static const int PARAMETER_BOOL = 1;
37
+ static const int PARAMETER_INTEGER = 2;
38
+ static const int PARAMETER_DOUBLE = 3;
39
+ static const int PARAMETER_STRING = 4;
40
+ static const int PARAMETER_BYTE_ARRAY = 5;
41
+ static const int PARAMETER_BOOL_ARRAY = 6;
42
+ static const int PARAMETER_INTEGER_ARRAY = 7;
43
+ static const int PARAMETER_DOUBLE_ARRAY = 8;
44
+ static const int PARAMETER_STRING_ARRAY = 9;
45
+
46
+ /*
47
+ Convert parsed ros arguments to parameters.
48
+
49
+ type Parameter = {
50
+ name: string,
51
+ type: number,
52
+ value: object
53
+ }
54
+
55
+ type Node = {
56
+ name: string,
57
+ parameters: array<Parameter>
58
+ }
59
+
60
+ parameters = array<Node>;
61
+ */
62
+ Napi::Object wrapParameters(Napi::Env env, rcl_params_t* parsed_args) {
63
+ Napi::Array nodes = Napi::Array::New(env);
64
+
65
+ // iterate over nodes
66
+ for (size_t i = 0; i < parsed_args->num_nodes; i++) {
67
+ Napi::Object node = Napi::Object::New(env);
68
+ node.Set("name", Napi::String::New(env, parsed_args->node_names[i]));
69
+
70
+ rcl_node_params_t node_parameters = parsed_args->params[i];
71
+
72
+ // iterate over node.parameters
73
+ Napi::Array parameters = Napi::Array::New(env);
74
+ for (size_t j = 0; j < node_parameters.num_params; j++) {
75
+ Napi::Object parameter = Napi::Object::New(env);
76
+
77
+ parameter.Set(
78
+ "name",
79
+ Napi::String::New(env, parsed_args->params[i].parameter_names[j]));
80
+
81
+ int param_type = PARAMETER_NOT_SET;
82
+
83
+ // for each value, find type & actual value
84
+ rcl_variant_t value = node_parameters.parameter_values[j];
85
+ if (value.bool_value != NULL) { // NOLINT()
86
+ param_type = PARAMETER_BOOL;
87
+ parameter.Set("value", Napi::Boolean::New(env, *value.bool_value));
88
+ } else if (value.integer_value != NULL) { // NOLINT()
89
+ param_type = PARAMETER_INTEGER;
90
+ parameter.Set("value", Napi::Number::New(env, *value.integer_value));
91
+ } else if (value.double_value != NULL) { // NOLINT()
92
+ param_type = PARAMETER_DOUBLE;
93
+ parameter.Set("value", Napi::Number::New(env, *value.double_value));
94
+ } else if (value.string_value != NULL) { // NOLINT()
95
+ param_type = PARAMETER_STRING;
96
+ parameter.Set("value", Napi::String::New(env, value.string_value));
97
+ } else if (value.bool_array_value != NULL) { // NOLINT()
98
+ param_type = PARAMETER_BOOL_ARRAY;
99
+ Napi::Array bool_array = Napi::Array::New(env);
100
+
101
+ for (size_t k = 0; k < value.bool_array_value->size; k++) {
102
+ bool_array.Set(
103
+ k, Napi::Boolean::New(env, value.bool_array_value->values[k]));
104
+ }
105
+ parameter.Set("value", bool_array);
106
+ } else if (value.string_array_value != NULL) { // NOLINT()
107
+ param_type = PARAMETER_STRING_ARRAY;
108
+ Napi::Array string_array = Napi::Array::New(env);
109
+ for (size_t k = 0; k < value.string_array_value->size; k++) {
110
+ string_array.Set(
111
+ k, Napi::String::New(env, value.string_array_value->data[k]));
112
+ }
113
+ parameter.Set("value", string_array);
114
+ } else if (value.byte_array_value != NULL) { // NOLINT()
115
+ param_type = PARAMETER_BYTE_ARRAY;
116
+ Napi::Array byte_array = Napi::Array::New(env);
117
+ for (size_t k = 0; k < value.byte_array_value->size; k++) {
118
+ byte_array.Set(
119
+ k, Napi::Number::New(env, value.byte_array_value->values[k]));
120
+ }
121
+ parameter.Set("value", byte_array);
122
+ } else if (value.integer_array_value != NULL) { // NOLINT()
123
+ param_type = PARAMETER_INTEGER_ARRAY;
124
+ Napi::Array int_array = Napi::Array::New(env);
125
+ for (size_t k = 0; k < value.integer_array_value->size; k++) {
126
+ int_array.Set(
127
+ k, Napi::Number::New(env, value.integer_array_value->values[k]));
128
+ }
129
+ parameter.Set("value", int_array);
130
+ } else if (value.double_array_value != NULL) { // NOLINT()
131
+ param_type = PARAMETER_DOUBLE_ARRAY;
132
+ Napi::Array dbl_array = Napi::Array::New(env);
133
+ for (size_t k = 0; k < value.double_array_value->size; k++) {
134
+ dbl_array.Set(
135
+ k, Napi::Number::New(env, value.double_array_value->values[k]));
136
+ }
137
+ parameter.Set("value", dbl_array);
138
+ }
139
+
140
+ parameter.Set("type", Napi::Number::New(env, param_type));
141
+ parameters.Set(j, parameter);
142
+ }
143
+
144
+ node.Set("parameters", parameters);
145
+ nodes.Set(i, node);
146
+ }
147
+
148
+ return nodes;
149
+ }
150
+
151
+ Napi::Value GetParameterOverrides(const Napi::CallbackInfo& info) {
152
+ Napi::Env env = info.Env();
153
+
154
+ RclHandle* context_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
155
+ rcl_context_t* context =
156
+ reinterpret_cast<rcl_context_t*>(context_handle->ptr());
157
+
158
+ rcl_arguments_t* parsed_args = &(context->global_arguments);
159
+ rcl_params_t* params = NULL;
160
+ THROW_ERROR_IF_NOT_EQUAL(
161
+ RCL_RET_OK, rcl_arguments_get_param_overrides(parsed_args, &params),
162
+ rcl_get_error_string().str);
163
+
164
+ if (params == NULL) {
165
+ return env.Undefined();
166
+ }
167
+
168
+ Napi::Object result = wrapParameters(env, params);
169
+
170
+ rcl_yaml_node_struct_fini(params);
171
+ return result;
172
+ }
173
+
174
+ Napi::Value CreateNode(const Napi::CallbackInfo& info) {
175
+ Napi::Env env = info.Env();
176
+
177
+ std::string node_name = info[0].As<Napi::String>().Utf8Value();
178
+ std::string name_space = info[1].As<Napi::String>().Utf8Value();
179
+ RclHandle* context_handle = RclHandle::Unwrap(info[2].As<Napi::Object>());
180
+ rcl_context_t* context =
181
+ reinterpret_cast<rcl_context_t*>(context_handle->ptr());
182
+
183
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(malloc(sizeof(rcl_node_t)));
184
+
185
+ *node = rcl_get_zero_initialized_node();
186
+ rcl_node_options_t options = rcl_node_get_default_options();
187
+
188
+ THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK,
189
+ rcl_node_init(node, node_name.c_str(),
190
+ name_space.c_str(), context, &options),
191
+ rcl_get_error_string().str);
192
+
193
+ auto handle = RclHandle::NewInstance(env, node, nullptr, [](void* ptr) {
194
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(ptr);
195
+ rcl_ret_t ret = rcl_node_fini(node);
196
+ free(ptr);
197
+ THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
198
+ });
199
+
200
+ return handle;
201
+ }
202
+
203
+ Napi::Value GetNodeName(const Napi::CallbackInfo& info) {
204
+ Napi::Env env = info.Env();
205
+
206
+ RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
207
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
208
+ const char* node_name = rcl_node_get_name(node);
209
+ if (!node_name) {
210
+ return env.Undefined();
211
+ } else {
212
+ return Napi::String::New(env, node_name);
213
+ }
214
+ }
215
+
216
+ Napi::Value GetNamespace(const Napi::CallbackInfo& info) {
217
+ Napi::Env env = info.Env();
218
+
219
+ RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
220
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
221
+ const char* node_namespace = rcl_node_get_namespace(node);
222
+ if (!node_namespace) {
223
+ return env.Undefined();
224
+ } else {
225
+ return Napi::String::New(env, node_namespace);
226
+ }
227
+ }
228
+
229
+ Napi::Value GetNodeLoggerName(const Napi::CallbackInfo& info) {
230
+ Napi::Env env = info.Env();
231
+
232
+ RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
233
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
234
+
235
+ const char* node_logger_name = rcl_node_get_logger_name(node);
236
+ if (!node_logger_name) {
237
+ return env.Undefined();
238
+ }
239
+
240
+ return Napi::String::New(env, node_logger_name);
241
+ }
242
+
243
+ Napi::Value ActionGetClientNamesAndTypesByNode(const Napi::CallbackInfo& info) {
244
+ Napi::Env env = info.Env();
245
+
246
+ RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
247
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
248
+ std::string node_name = info[1].As<Napi::String>().Utf8Value();
249
+ std::string node_namespace = info[2].As<Napi::String>().Utf8Value();
250
+
251
+ rcl_names_and_types_t names_and_types =
252
+ rcl_get_zero_initialized_names_and_types();
253
+ rcl_allocator_t allocator = rcl_get_default_allocator();
254
+ THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK,
255
+ rcl_action_get_client_names_and_types_by_node(
256
+ node, &allocator, node_name.c_str(),
257
+ node_namespace.c_str(), &names_and_types),
258
+ "Failed to action client names and types.");
259
+
260
+ Napi::Array result_list = Napi::Array::New(env, names_and_types.names.size);
261
+ ExtractNamesAndTypes(names_and_types, &result_list);
262
+
263
+ THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK,
264
+ rcl_names_and_types_fini(&names_and_types),
265
+ "Failed to destroy names_and_types");
266
+
267
+ return result_list;
268
+ }
269
+
270
+ Napi::Value ActionGetServerNamesAndTypesByNode(const Napi::CallbackInfo& info) {
271
+ Napi::Env env = info.Env();
272
+
273
+ RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
274
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
275
+ std::string node_name = info[1].As<Napi::String>().Utf8Value();
276
+ std::string node_namespace = info[2].As<Napi::String>().Utf8Value();
277
+
278
+ rcl_names_and_types_t names_and_types =
279
+ rcl_get_zero_initialized_names_and_types();
280
+ rcl_allocator_t allocator = rcl_get_default_allocator();
281
+ THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK,
282
+ rcl_action_get_server_names_and_types_by_node(
283
+ node, &allocator, node_name.c_str(),
284
+ node_namespace.c_str(), &names_and_types),
285
+ "Failed to action server names and types");
286
+
287
+ Napi::Array result_list = Napi::Array::New(env, names_and_types.names.size);
288
+ ExtractNamesAndTypes(names_and_types, &result_list);
289
+
290
+ THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK,
291
+ rcl_names_and_types_fini(&names_and_types),
292
+ "Failed to destroy names_and_types");
293
+
294
+ return result_list;
295
+ }
296
+
297
+ Napi::Value ActionGetNamesAndTypes(const Napi::CallbackInfo& info) {
298
+ Napi::Env env = info.Env();
299
+
300
+ RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
301
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
302
+
303
+ rcl_names_and_types_t names_and_types =
304
+ rcl_get_zero_initialized_names_and_types();
305
+ rcl_allocator_t allocator = rcl_get_default_allocator();
306
+ THROW_ERROR_IF_NOT_EQUAL(
307
+ RCL_RET_OK,
308
+ rcl_action_get_names_and_types(node, &allocator, &names_and_types),
309
+ "Failed to action server names and types");
310
+
311
+ Napi::Array result_list = Napi::Array::New(env, names_and_types.names.size);
312
+ ExtractNamesAndTypes(names_and_types, &result_list);
313
+
314
+ THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK,
315
+ rcl_names_and_types_fini(&names_and_types),
316
+ "Failed to destroy names_and_types");
317
+
318
+ return result_list;
319
+ }
320
+
321
+ Napi::Value CountPublishers(const Napi::CallbackInfo& info) {
322
+ Napi::Env env = info.Env();
323
+
324
+ RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
325
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
326
+ std::string topic_name = info[1].As<Napi::String>().Utf8Value();
327
+
328
+ size_t count = 0;
329
+ THROW_ERROR_IF_NOT_EQUAL(
330
+ RCL_RET_OK, rcl_count_publishers(node, topic_name.c_str(), &count),
331
+ "Failed to count publishers.");
332
+
333
+ return Napi::Number::New(env, static_cast<int32_t>(count));
334
+ }
335
+
336
+ Napi::Value CountSubscribers(const Napi::CallbackInfo& info) {
337
+ Napi::Env env = info.Env();
338
+
339
+ RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
340
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
341
+ std::string topic_name = info[1].As<Napi::String>().Utf8Value();
342
+
343
+ size_t count = 0;
344
+ THROW_ERROR_IF_NOT_EQUAL(
345
+ RCL_RET_OK, rcl_count_subscribers(node, topic_name.c_str(), &count),
346
+ "Failed to count subscribers.");
347
+
348
+ return Napi::Number::New(env, static_cast<int32_t>(count));
349
+ }
350
+
351
+ #if ROS_VERSION > 2205 // 2205 == Humble
352
+ Napi::Value CountClients(const Napi::CallbackInfo& info) {
353
+ Napi::Env env = info.Env();
354
+
355
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(
356
+ RclHandle::Unwrap(info[0].As<Napi::Object>())->ptr());
357
+ std::string service_name = info[1].As<Napi::String>().Utf8Value();
358
+
359
+ size_t count = 0;
360
+ THROW_ERROR_IF_NOT_EQUAL(
361
+ rcl_count_clients(node, service_name.c_str(), &count), RCL_RET_OK,
362
+ rcl_get_error_string().str);
363
+
364
+ return Napi::Number::New(env, count);
365
+ }
366
+
367
+ Napi::Value CountServices(const Napi::CallbackInfo& info) {
368
+ Napi::Env env = info.Env();
369
+
370
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(
371
+ RclHandle::Unwrap(info[0].As<Napi::Object>())->ptr());
372
+ std::string service_name = info[1].As<Napi::String>().Utf8Value();
373
+
374
+ size_t count = 0;
375
+ THROW_ERROR_IF_NOT_EQUAL(
376
+ rcl_count_services(node, service_name.c_str(), &count), RCL_RET_OK,
377
+ rcl_get_error_string().str);
378
+
379
+ return Napi::Number::New(env, count);
380
+ }
381
+ #endif
382
+
383
+ Napi::Value GetNodeNames(const Napi::CallbackInfo& info) {
384
+ Napi::Env env = info.Env();
385
+
386
+ RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
387
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
388
+ rcutils_string_array_t node_names =
389
+ rcutils_get_zero_initialized_string_array();
390
+ rcutils_string_array_t node_namespaces =
391
+ rcutils_get_zero_initialized_string_array();
392
+ rcl_allocator_t allocator = rcl_get_default_allocator();
393
+
394
+ THROW_ERROR_IF_NOT_EQUAL(
395
+ RCL_RET_OK,
396
+ rcl_get_node_names(node, allocator, &node_names, &node_namespaces),
397
+ "Failed to get_node_names.");
398
+
399
+ Napi::Array result_list = Napi::Array::New(env, node_names.size);
400
+
401
+ for (size_t i = 0; i < node_names.size; ++i) {
402
+ Napi::Object item = Napi::Object::New(env);
403
+
404
+ item.Set("name", Napi::String::New(env, node_names.data[i]));
405
+ item.Set("namespace", Napi::String::New(env, node_namespaces.data[i]));
406
+
407
+ result_list.Set(i, item);
408
+ }
409
+
410
+ rcutils_ret_t fini_names_ret = rcutils_string_array_fini(&node_names);
411
+ rcutils_ret_t fini_namespaces_ret =
412
+ rcutils_string_array_fini(&node_namespaces);
413
+
414
+ THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, fini_names_ret,
415
+ "Failed to destroy node_names");
416
+ THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, fini_namespaces_ret,
417
+ "Failed to destroy node_namespaces");
418
+
419
+ return result_list;
420
+ }
421
+
422
+ Napi::Object InitNodeBindings(Napi::Env env, Napi::Object exports) {
423
+ exports.Set("getParameterOverrides",
424
+ Napi::Function::New(env, GetParameterOverrides));
425
+ exports.Set("createNode", Napi::Function::New(env, CreateNode));
426
+ exports.Set("getNodeName", Napi::Function::New(env, GetNodeName));
427
+ exports.Set("getNamespace", Napi::Function::New(env, GetNamespace));
428
+ exports.Set("getNodeLoggerName", Napi::Function::New(env, GetNodeLoggerName));
429
+ exports.Set("actionGetClientNamesAndTypesByNode",
430
+ Napi::Function::New(env, ActionGetClientNamesAndTypesByNode));
431
+ exports.Set("actionGetServerNamesAndTypesByNode",
432
+ Napi::Function::New(env, ActionGetServerNamesAndTypesByNode));
433
+ exports.Set("actionGetNamesAndTypes",
434
+ Napi::Function::New(env, ActionGetNamesAndTypes));
435
+ exports.Set("countPublishers", Napi::Function::New(env, CountPublishers));
436
+ exports.Set("countSubscribers", Napi::Function::New(env, CountSubscribers));
437
+ #if ROS_VERSION > 2205 // 2205 == Humble
438
+ exports.Set("countClients", Napi::Function::New(env, CountClients));
439
+ exports.Set("countServices", Napi::Function::New(env, CountServices));
440
+ #endif
441
+ exports.Set("getNodeNames", Napi::Function::New(env, GetNodeNames));
442
+ return exports;
443
+ }
444
+
445
+ } // namespace rclnodejs
446
+
447
+ #endif // SRC_RCL_NODE_BINDINGS_H_
@@ -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_NODE_BINDINGS_H_
16
+ #define SRC_RCL_NODE_BINDINGS_H_
17
+
18
+ #include <napi.h>
19
+
20
+ namespace rclnodejs {
21
+
22
+ Napi::Object InitNodeBindings(Napi::Env env, Napi::Object exports);
23
+
24
+ }
25
+
26
+ #endif // SRC_RCL_NODE_BINDINGS_H_
@@ -0,0 +1,141 @@
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_publisher_bindings.h"
16
+
17
+ #include <rcl/error_handling.h>
18
+ #include <rcl/rcl.h>
19
+
20
+ #include <string>
21
+
22
+ #include "macros.h"
23
+ #include "rcl_handle.h"
24
+ #include "rcl_utilities.h"
25
+
26
+ namespace rclnodejs {
27
+
28
+ Napi::Value CreatePublisher(const Napi::CallbackInfo& info) {
29
+ Napi::Env env = info.Env();
30
+
31
+ RclHandle* node_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
32
+ rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
33
+
34
+ std::string package_name = info[1].As<Napi::String>().Utf8Value();
35
+ std::string message_sub_folder = info[2].As<Napi::String>().Utf8Value();
36
+ std::string message_name = info[3].As<Napi::String>().Utf8Value();
37
+ std::string topic = info[4].As<Napi::String>().Utf8Value();
38
+
39
+ rcl_publisher_t* publisher =
40
+ reinterpret_cast<rcl_publisher_t*>(malloc(sizeof(rcl_publisher_t)));
41
+ *publisher = rcl_get_zero_initialized_publisher();
42
+
43
+ const rosidl_message_type_support_t* ts =
44
+ GetMessageTypeSupport(package_name, message_sub_folder, message_name);
45
+
46
+ if (ts) {
47
+ rcl_publisher_options_t publisher_ops = rcl_publisher_get_default_options();
48
+ auto qos_profile = GetQoSProfile(info[5]);
49
+
50
+ if (qos_profile) {
51
+ publisher_ops.qos = *qos_profile;
52
+ }
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);
57
+
58
+ auto js_obj =
59
+ RclHandle::NewInstance(env, publisher, node_handle, [node](void* ptr) {
60
+ rcl_publisher_t* publisher = reinterpret_cast<rcl_publisher_t*>(ptr);
61
+ rcl_ret_t ret = rcl_publisher_fini(publisher, node);
62
+ free(ptr);
63
+ THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK, ret, rcl_get_error_string().str);
64
+ });
65
+
66
+ return js_obj;
67
+ } else {
68
+ Napi::Error::New(env, GetErrorMessageAndClear())
69
+ .ThrowAsJavaScriptException();
70
+ return env.Undefined();
71
+ }
72
+ }
73
+
74
+ Napi::Value Publish(const Napi::CallbackInfo& info) {
75
+ Napi::Env env = info.Env();
76
+
77
+ rcl_publisher_t* publisher = reinterpret_cast<rcl_publisher_t*>(
78
+ RclHandle::Unwrap(info[0].As<Napi::Object>())->ptr());
79
+
80
+ void* buffer = info[1].As<Napi::Buffer<char>>().Data();
81
+ THROW_ERROR_IF_NOT_EQUAL(rcl_publish(publisher, buffer, nullptr), RCL_RET_OK,
82
+ rcl_get_error_string().str);
83
+
84
+ return env.Undefined();
85
+ }
86
+
87
+ Napi::Value GetPublisherTopic(const Napi::CallbackInfo& info) {
88
+ Napi::Env env = info.Env();
89
+
90
+ rcl_publisher_t* publisher = reinterpret_cast<rcl_publisher_t*>(
91
+ RclHandle::Unwrap(info[0].As<Napi::Object>())->ptr());
92
+
93
+ const char* topic = rcl_publisher_get_topic_name(publisher);
94
+ return Napi::String::New(env, topic);
95
+ }
96
+
97
+ Napi::Value PublishRawMessage(const Napi::CallbackInfo& info) {
98
+ Napi::Env env = info.Env();
99
+
100
+ rcl_publisher_t* publisher = reinterpret_cast<rcl_publisher_t*>(
101
+ RclHandle::Unwrap(info[0].As<Napi::Object>())->ptr());
102
+
103
+ auto object = info[1].As<Napi::Buffer<char>>();
104
+ rcl_serialized_message_t serialized_msg =
105
+ rmw_get_zero_initialized_serialized_message();
106
+ serialized_msg.buffer_capacity = object.Length();
107
+ serialized_msg.buffer_length = serialized_msg.buffer_capacity;
108
+ serialized_msg.buffer = reinterpret_cast<uint8_t*>(object.Data());
109
+
110
+ THROW_ERROR_IF_NOT_EQUAL(
111
+ rcl_publish_serialized_message(publisher, &serialized_msg, nullptr),
112
+ RCL_RET_OK, rcl_get_error_string().str);
113
+
114
+ return env.Undefined();
115
+ }
116
+
117
+ Napi::Value GetSubscriptionCount(const Napi::CallbackInfo& info) {
118
+ Napi::Env env = info.Env();
119
+
120
+ rcl_publisher_t* publisher = reinterpret_cast<rcl_publisher_t*>(
121
+ RclHandle::Unwrap(info[0].As<Napi::Object>())->ptr());
122
+
123
+ size_t count = 0;
124
+ THROW_ERROR_IF_NOT_EQUAL(
125
+ rcl_publisher_get_subscription_count(publisher, &count), RCL_RET_OK,
126
+ rcl_get_error_string().str);
127
+
128
+ return Napi::Number::New(env, count);
129
+ }
130
+
131
+ Napi::Object InitPublisherBindings(Napi::Env env, Napi::Object exports) {
132
+ exports.Set("createPublisher", Napi::Function::New(env, CreatePublisher));
133
+ exports.Set("publish", Napi::Function::New(env, Publish));
134
+ exports.Set("getPublisherTopic", Napi::Function::New(env, GetPublisherTopic));
135
+ exports.Set("publishRawMessage", Napi::Function::New(env, PublishRawMessage));
136
+ exports.Set("getSubscriptionCount",
137
+ Napi::Function::New(env, GetSubscriptionCount));
138
+ return exports;
139
+ }
140
+
141
+ } // 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_PUBLISHER_BINDINGS_H_
16
+ #define SRC_RCL_PUBLISHER_BINDINGS_H_
17
+
18
+ #include <napi.h>
19
+
20
+ namespace rclnodejs {
21
+
22
+ Napi::Object InitPublisherBindings(Napi::Env env, Napi::Object exports);
23
+
24
+ }
25
+
26
+ #endif // SRC_RCL_PUBLISHER_BINDINGS_H_