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.
- package/README.md +4 -4
- package/binding.gyp +5 -0
- package/index.js +26 -3
- package/lib/context.js +4 -2
- package/lib/event_handler.js +474 -0
- package/lib/lifecycle.js +9 -0
- package/lib/lifecycle_publisher.js +2 -2
- package/lib/node.js +163 -28
- package/lib/publisher.js +31 -4
- package/lib/serialization.js +60 -0
- package/lib/subscription.js +48 -4
- package/lib/type_description_service.js +27 -1
- package/package.json +1 -1
- package/rosidl_gen/templates/message.dot +1 -1
- package/scripts/npmjs-readme.md +4 -4
- package/src/addon.cpp +4 -0
- package/src/executor.cpp +3 -4
- package/src/handle_manager.cpp +13 -2
- package/src/handle_manager.h +4 -1
- package/src/macros.h +17 -1
- package/src/rcl_action_client_bindings.cpp +3 -2
- package/src/rcl_action_goal_bindings.cpp +3 -2
- package/src/rcl_action_server_bindings.cpp +7 -5
- package/src/rcl_client_bindings.cpp +4 -3
- package/src/rcl_context_bindings.cpp +29 -19
- package/src/rcl_event_handle_bindings.cpp +294 -0
- package/src/rcl_event_handle_bindings.h +26 -0
- package/src/rcl_guard_condition_bindings.cpp +3 -2
- package/src/rcl_lifecycle_bindings.cpp +18 -4
- package/src/rcl_node_bindings.cpp +111 -3
- package/src/rcl_publisher_bindings.cpp +4 -3
- package/src/rcl_serialization_bindings.cpp +116 -0
- package/src/rcl_serialization_bindings.h +26 -0
- package/src/rcl_service_bindings.cpp +4 -3
- package/src/rcl_subscription_bindings.cpp +3 -2
- package/src/rcl_time_point_bindings.cpp +3 -2
- package/src/rcl_timer_bindings.cpp +8 -6
- package/src/rcl_utilities.cpp +31 -0
- package/src/rcl_utilities.h +7 -0
- package/tsconfig.json +2 -2
- package/types/context.d.ts +3 -2
- package/types/index.d.ts +26 -1
- package/types/lifecycle.d.ts +7 -0
- package/types/node.d.ts +60 -10
package/src/executor.cpp
CHANGED
|
@@ -190,10 +190,11 @@ RclResult Executor::WaitForReadyCallbacks(rcl_wait_set_t* wait_set,
|
|
|
190
190
|
size_t num_timers = 0u;
|
|
191
191
|
size_t num_clients = 0u;
|
|
192
192
|
size_t num_services = 0u;
|
|
193
|
+
size_t num_events = 0u;
|
|
193
194
|
|
|
194
195
|
rcl_ret_t get_entity_ret = handle_manager_->GetEntityCounts(
|
|
195
196
|
&num_subscriptions, &num_guard_conditions, &num_timers, &num_clients,
|
|
196
|
-
&num_services);
|
|
197
|
+
&num_services, &num_events);
|
|
197
198
|
if (get_entity_ret != RCL_RET_OK) {
|
|
198
199
|
std::string error_message = std::string("Failed to get entity counts: ") +
|
|
199
200
|
std::string(rcl_get_error_string().str);
|
|
@@ -202,9 +203,7 @@ RclResult Executor::WaitForReadyCallbacks(rcl_wait_set_t* wait_set,
|
|
|
202
203
|
|
|
203
204
|
rcl_ret_t resize_ret =
|
|
204
205
|
rcl_wait_set_resize(wait_set, num_subscriptions, num_guard_conditions,
|
|
205
|
-
num_timers, num_clients, num_services,
|
|
206
|
-
// TODO(minggang): support events.
|
|
207
|
-
0u);
|
|
206
|
+
num_timers, num_clients, num_services, num_events);
|
|
208
207
|
if (resize_ret != RCL_RET_OK) {
|
|
209
208
|
std::string error_message = std::string("Failed to resize: ") +
|
|
210
209
|
std::string(rcl_get_error_string().str);
|
package/src/handle_manager.cpp
CHANGED
|
@@ -40,7 +40,6 @@ HandleManager::~HandleManager() {
|
|
|
40
40
|
|
|
41
41
|
void HandleManager::SynchronizeHandles(const Napi::Object& node) {
|
|
42
42
|
Napi::HandleScope scope(node.Env());
|
|
43
|
-
|
|
44
43
|
Napi::Value timers = node.Get("_timers");
|
|
45
44
|
Napi::Value subscriptions = node.Get("_subscriptions");
|
|
46
45
|
Napi::Value clients = node.Get("_clients");
|
|
@@ -48,6 +47,7 @@ void HandleManager::SynchronizeHandles(const Napi::Object& node) {
|
|
|
48
47
|
Napi::Value guard_conditions = node.Get("_guards");
|
|
49
48
|
Napi::Value action_clients = node.Get("_actionClients");
|
|
50
49
|
Napi::Value action_servers = node.Get("_actionServers");
|
|
50
|
+
Napi::Value events = node.Get("_events");
|
|
51
51
|
|
|
52
52
|
uint32_t sum = 0;
|
|
53
53
|
is_synchronizing_.store(true);
|
|
@@ -66,6 +66,7 @@ void HandleManager::SynchronizeHandles(const Napi::Object& node) {
|
|
|
66
66
|
&action_clients_);
|
|
67
67
|
sum += SynchronizeHandlesByType(action_servers.As<Napi::Object>(),
|
|
68
68
|
&action_servers_);
|
|
69
|
+
sum += SynchronizeHandlesByType(events.As<Napi::Object>(), &events_);
|
|
69
70
|
}
|
|
70
71
|
is_synchronizing_.store(false);
|
|
71
72
|
|
|
@@ -98,6 +99,7 @@ void HandleManager::ClearHandles() {
|
|
|
98
99
|
guard_conditions_.clear();
|
|
99
100
|
action_clients_.clear();
|
|
100
101
|
action_servers_.clear();
|
|
102
|
+
events_.clear();
|
|
101
103
|
}
|
|
102
104
|
|
|
103
105
|
rcl_ret_t HandleManager::AddHandlesToWaitSet(rcl_wait_set_t* wait_set) {
|
|
@@ -152,6 +154,11 @@ rcl_ret_t HandleManager::AddHandlesToWaitSet(rcl_wait_set_t* wait_set) {
|
|
|
152
154
|
if (ret != RCL_RET_OK) return ret;
|
|
153
155
|
}
|
|
154
156
|
|
|
157
|
+
for (auto& event : events_) {
|
|
158
|
+
rcl_event_t* rcl_event = reinterpret_cast<rcl_event_t*>(event->ptr());
|
|
159
|
+
rcl_ret_t ret = rcl_wait_set_add_event(wait_set, rcl_event, nullptr);
|
|
160
|
+
if (ret != RCL_RET_OK) return ret;
|
|
161
|
+
}
|
|
155
162
|
return RCL_RET_OK;
|
|
156
163
|
}
|
|
157
164
|
|
|
@@ -169,6 +176,8 @@ rcl_ret_t HandleManager::CollectReadyHandles(rcl_wait_set_t* wait_set) {
|
|
|
169
176
|
CollectReadyHandlesByType(wait_set->guard_conditions,
|
|
170
177
|
wait_set->size_of_guard_conditions,
|
|
171
178
|
guard_conditions_, &ready_handles);
|
|
179
|
+
CollectReadyHandlesByType(wait_set->events, wait_set->size_of_events, events_,
|
|
180
|
+
&ready_handles);
|
|
172
181
|
|
|
173
182
|
rcl_ret_t ret = CollectReadyActionHandles(wait_set, &ready_handles);
|
|
174
183
|
if (!ready_handles.empty()) {
|
|
@@ -184,7 +193,8 @@ rcl_ret_t HandleManager::GetEntityCounts(size_t* subscriptions_size,
|
|
|
184
193
|
size_t* guard_conditions_size,
|
|
185
194
|
size_t* timers_size,
|
|
186
195
|
size_t* clients_size,
|
|
187
|
-
size_t* services_size
|
|
196
|
+
size_t* services_size,
|
|
197
|
+
size_t* events_size) {
|
|
188
198
|
size_t num_subscriptions = 0u;
|
|
189
199
|
size_t num_guard_conditions = 0u;
|
|
190
200
|
size_t num_timers = 0u;
|
|
@@ -230,6 +240,7 @@ rcl_ret_t HandleManager::GetEntityCounts(size_t* subscriptions_size,
|
|
|
230
240
|
*timers_size += timer_count();
|
|
231
241
|
*clients_size += client_count();
|
|
232
242
|
*services_size += service_count();
|
|
243
|
+
*events_size += event_count();
|
|
233
244
|
|
|
234
245
|
return RCL_RET_OK;
|
|
235
246
|
}
|
package/src/handle_manager.h
CHANGED
|
@@ -68,13 +68,15 @@ class HandleManager {
|
|
|
68
68
|
rcl_ret_t CollectReadyHandles(rcl_wait_set_t* wait_set);
|
|
69
69
|
rcl_ret_t GetEntityCounts(size_t* subscriptions_size,
|
|
70
70
|
size_t* guard_conditions_size, size_t* timers_size,
|
|
71
|
-
size_t* clients_size, size_t* services_size
|
|
71
|
+
size_t* clients_size, size_t* services_size,
|
|
72
|
+
size_t* events_size);
|
|
72
73
|
|
|
73
74
|
uint32_t subscription_count() const { return subscriptions_.size(); }
|
|
74
75
|
uint32_t service_count() const { return services_.size(); }
|
|
75
76
|
uint32_t client_count() const { return clients_.size(); }
|
|
76
77
|
uint32_t timer_count() const { return timers_.size(); }
|
|
77
78
|
uint32_t guard_condition_count() const { return guard_conditions_.size(); }
|
|
79
|
+
uint32_t event_count() const { return events_.size(); }
|
|
78
80
|
uv_rwlock_t* handle_rwlock() { return &sync_handles_rwlock_; }
|
|
79
81
|
|
|
80
82
|
uint32_t ready_handles_count();
|
|
@@ -110,6 +112,7 @@ class HandleManager {
|
|
|
110
112
|
std::vector<rclnodejs::RclHandle*> action_servers_;
|
|
111
113
|
std::vector<rclnodejs::RclHandle*> action_clients_;
|
|
112
114
|
std::vector<rclnodejs::RclHandle*> ready_handles_;
|
|
115
|
+
std::vector<rclnodejs::RclHandle*> events_;
|
|
113
116
|
|
|
114
117
|
// Protects the handles.
|
|
115
118
|
uv_rwlock_t sync_handles_rwlock_;
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
#include <rcl/logging.h>
|
|
18
18
|
#include <rcl/rcl.h>
|
|
19
19
|
|
|
20
|
-
#include <
|
|
20
|
+
#include <rcpputils/scope_exit.hpp>
|
|
21
|
+
// NOLINTNEXTLINE
|
|
21
22
|
#include <string>
|
|
22
23
|
|
|
23
24
|
#include "macros.h"
|
|
@@ -35,6 +36,15 @@ Napi::Value Init(const Napi::CallbackInfo& info) {
|
|
|
35
36
|
rcl_init_options_init(&init_options, allocator),
|
|
36
37
|
rcl_get_error_string().str);
|
|
37
38
|
|
|
39
|
+
RCPPUTILS_SCOPE_EXIT({
|
|
40
|
+
rcl_ret_t fini_ret = rcl_init_options_fini(&init_options);
|
|
41
|
+
if (RCL_RET_OK != fini_ret) {
|
|
42
|
+
Napi::Error::New(env, rcl_get_error_string().str)
|
|
43
|
+
.ThrowAsJavaScriptException();
|
|
44
|
+
rcl_reset_error();
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
38
48
|
// Preprocess Context
|
|
39
49
|
RclHandle* context_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
40
50
|
rcl_context_t* context =
|
|
@@ -42,17 +52,20 @@ Napi::Value Init(const Napi::CallbackInfo& info) {
|
|
|
42
52
|
|
|
43
53
|
// Preprocess argc & argv
|
|
44
54
|
Napi::Array jsArgv = info[1].As<Napi::Array>();
|
|
45
|
-
|
|
46
|
-
char** argv =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
size_t argc = jsArgv.Length();
|
|
56
|
+
char** argv = AbstractArgsFromNapiArray(jsArgv);
|
|
57
|
+
|
|
58
|
+
// Set up the domain id.
|
|
59
|
+
size_t domain_id = RCL_DEFAULT_DOMAIN_ID;
|
|
60
|
+
if (info.Length() > 2 && info[2].IsBigInt()) {
|
|
61
|
+
bool lossless;
|
|
62
|
+
domain_id = info[2].As<Napi::BigInt>().Uint64Value(&lossless);
|
|
63
|
+
}
|
|
64
|
+
rcl_ret_t ret = rcl_init_options_set_domain_id(&init_options, domain_id);
|
|
65
|
+
if (RCL_RET_OK != ret) {
|
|
66
|
+
Napi::Error::New(env, "failed to set domain id to init options")
|
|
67
|
+
.ThrowAsJavaScriptException();
|
|
68
|
+
return env.Undefined();
|
|
56
69
|
}
|
|
57
70
|
|
|
58
71
|
THROW_ERROR_IF_NOT_EQUAL(
|
|
@@ -64,11 +77,7 @@ Napi::Value Init(const Napi::CallbackInfo& info) {
|
|
|
64
77
|
RCL_RET_OK, rcl_logging_configure(&context->global_arguments, &allocator),
|
|
65
78
|
rcl_get_error_string().str);
|
|
66
79
|
|
|
67
|
-
|
|
68
|
-
free(argv[i]);
|
|
69
|
-
}
|
|
70
|
-
free(argv);
|
|
71
|
-
|
|
80
|
+
RCPPUTILS_SCOPE_EXIT({ FreeArgs(argv, argc); });
|
|
72
81
|
return env.Undefined();
|
|
73
82
|
}
|
|
74
83
|
|
|
@@ -111,7 +120,8 @@ Napi::Value CreateContext(const Napi::CallbackInfo& info) {
|
|
|
111
120
|
rcl_context_t* context = reinterpret_cast<rcl_context_t*>(ptr);
|
|
112
121
|
rcl_ret_t ret = DestroyContext(env, context);
|
|
113
122
|
free(ptr);
|
|
114
|
-
|
|
123
|
+
THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
|
|
124
|
+
rcl_get_error_string().str);
|
|
115
125
|
});
|
|
116
126
|
|
|
117
127
|
return js_obj;
|
|
@@ -141,7 +151,7 @@ Napi::Value GetDomainId(const Napi::CallbackInfo& info) {
|
|
|
141
151
|
return env.Undefined();
|
|
142
152
|
}
|
|
143
153
|
|
|
144
|
-
return Napi::
|
|
154
|
+
return Napi::BigInt::New(env, domain_id);
|
|
145
155
|
}
|
|
146
156
|
|
|
147
157
|
Napi::Object InitContextBindings(Napi::Env env, Napi::Object exports) {
|
|
@@ -0,0 +1,294 @@
|
|
|
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_event_handle_bindings.h"
|
|
16
|
+
|
|
17
|
+
#include <rcl/error_handling.h>
|
|
18
|
+
#include <rcl/rcl.h>
|
|
19
|
+
|
|
20
|
+
#include "rcl_handle.h"
|
|
21
|
+
|
|
22
|
+
namespace {
|
|
23
|
+
|
|
24
|
+
typedef union event_callback_data {
|
|
25
|
+
// Subscription events
|
|
26
|
+
rmw_requested_deadline_missed_status_t requested_deadline_missed;
|
|
27
|
+
rmw_liveliness_changed_status_t liveliness_changed;
|
|
28
|
+
rmw_message_lost_status_t message_lost;
|
|
29
|
+
rmw_requested_qos_incompatible_event_status_t requested_incompatible_qos;
|
|
30
|
+
rmw_matched_status_t subscription_matched;
|
|
31
|
+
// Publisher events
|
|
32
|
+
rmw_offered_deadline_missed_status_t offered_deadline_missed;
|
|
33
|
+
rmw_liveliness_lost_status_t liveliness_lost;
|
|
34
|
+
rmw_offered_qos_incompatible_event_status_t offered_incompatible_qos;
|
|
35
|
+
rmw_matched_status_t publisher_matched;
|
|
36
|
+
|
|
37
|
+
rmw_incompatible_type_status_t incompatible_type;
|
|
38
|
+
} event_callback_data_t;
|
|
39
|
+
|
|
40
|
+
rcl_event_t* CreateEventHandle() {
|
|
41
|
+
rcl_event_t* event =
|
|
42
|
+
reinterpret_cast<rcl_event_t*>(malloc(sizeof(rcl_event_t)));
|
|
43
|
+
*event = rcl_get_zero_initialized_event();
|
|
44
|
+
return event;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
Napi::Value CreateJSObjectForSubscriptionEvent(
|
|
48
|
+
Napi::Env env, rcl_subscription_event_type_t subscription_event_type,
|
|
49
|
+
const event_callback_data_t& data) {
|
|
50
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
51
|
+
switch (subscription_event_type) {
|
|
52
|
+
case RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED: {
|
|
53
|
+
obj.Set(
|
|
54
|
+
"total_count",
|
|
55
|
+
Napi::Number::New(env, data.requested_deadline_missed.total_count));
|
|
56
|
+
obj.Set("total_count_change",
|
|
57
|
+
Napi::Number::New(
|
|
58
|
+
env, data.requested_deadline_missed.total_count_change));
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
case RCL_SUBSCRIPTION_LIVELINESS_CHANGED: {
|
|
62
|
+
obj.Set("alive_count",
|
|
63
|
+
Napi::Number::New(env, data.liveliness_changed.alive_count));
|
|
64
|
+
obj.Set("not_alive_count",
|
|
65
|
+
Napi::Number::New(env, data.liveliness_changed.not_alive_count));
|
|
66
|
+
obj.Set(
|
|
67
|
+
"alive_count_change",
|
|
68
|
+
Napi::Number::New(env, data.liveliness_changed.alive_count_change));
|
|
69
|
+
obj.Set("not_alive_count_change",
|
|
70
|
+
Napi::Number::New(
|
|
71
|
+
env, data.liveliness_changed.not_alive_count_change));
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case RCL_SUBSCRIPTION_MESSAGE_LOST: {
|
|
75
|
+
obj.Set("total_count",
|
|
76
|
+
Napi::Number::New(env, data.message_lost.total_count));
|
|
77
|
+
obj.Set("total_count_change",
|
|
78
|
+
Napi::Number::New(env, data.message_lost.total_count_change));
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
case RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS: {
|
|
82
|
+
obj.Set(
|
|
83
|
+
"total_count",
|
|
84
|
+
Napi::Number::New(env, data.requested_incompatible_qos.total_count));
|
|
85
|
+
obj.Set("total_count_change",
|
|
86
|
+
Napi::Number::New(
|
|
87
|
+
env, data.requested_incompatible_qos.total_count_change));
|
|
88
|
+
obj.Set("last_policy_kind",
|
|
89
|
+
Napi::Number::New(
|
|
90
|
+
env, data.requested_incompatible_qos.last_policy_kind));
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case RCL_SUBSCRIPTION_INCOMPATIBLE_TYPE: {
|
|
94
|
+
obj.Set("total_count",
|
|
95
|
+
Napi::Number::New(env, data.incompatible_type.total_count));
|
|
96
|
+
obj.Set(
|
|
97
|
+
"total_count_change",
|
|
98
|
+
Napi::Number::New(env, data.incompatible_type.total_count_change));
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case RCL_SUBSCRIPTION_MATCHED: {
|
|
102
|
+
obj.Set("total_count",
|
|
103
|
+
Napi::Number::New(env, data.subscription_matched.total_count));
|
|
104
|
+
obj.Set(
|
|
105
|
+
"total_count_change",
|
|
106
|
+
Napi::Number::New(env, data.subscription_matched.total_count_change));
|
|
107
|
+
obj.Set("current_count",
|
|
108
|
+
Napi::Number::New(env, data.subscription_matched.current_count));
|
|
109
|
+
obj.Set("current_count_change",
|
|
110
|
+
Napi::Number::New(
|
|
111
|
+
env, data.subscription_matched.current_count_change));
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
default:
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
return obj;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
Napi::Value CreateJSObjectForPublisherEvent(
|
|
121
|
+
Napi::Env env, rcl_publisher_event_type_t publisher_event_type,
|
|
122
|
+
const event_callback_data_t& data) {
|
|
123
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
124
|
+
switch (publisher_event_type) {
|
|
125
|
+
case RCL_PUBLISHER_OFFERED_DEADLINE_MISSED: {
|
|
126
|
+
obj.Set("total_count",
|
|
127
|
+
Napi::Number::New(env, data.offered_deadline_missed.total_count));
|
|
128
|
+
obj.Set("total_count_change",
|
|
129
|
+
Napi::Number::New(
|
|
130
|
+
env, data.offered_deadline_missed.total_count_change));
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
case RCL_PUBLISHER_LIVELINESS_LOST: {
|
|
134
|
+
obj.Set("total_count",
|
|
135
|
+
Napi::Number::New(env, data.liveliness_lost.total_count));
|
|
136
|
+
obj.Set("total_count_change",
|
|
137
|
+
Napi::Number::New(env, data.liveliness_lost.total_count_change));
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
case RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS: {
|
|
141
|
+
obj.Set(
|
|
142
|
+
"total_count",
|
|
143
|
+
Napi::Number::New(env, data.offered_incompatible_qos.total_count));
|
|
144
|
+
obj.Set("total_count_change",
|
|
145
|
+
Napi::Number::New(
|
|
146
|
+
env, data.offered_incompatible_qos.total_count_change));
|
|
147
|
+
obj.Set("last_policy_kind",
|
|
148
|
+
Napi::Number::New(
|
|
149
|
+
env, data.offered_incompatible_qos.last_policy_kind));
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case RCL_PUBLISHER_INCOMPATIBLE_TYPE: {
|
|
153
|
+
obj.Set("total_count",
|
|
154
|
+
Napi::Number::New(env, data.incompatible_type.total_count));
|
|
155
|
+
obj.Set(
|
|
156
|
+
"total_count_change",
|
|
157
|
+
Napi::Number::New(env, data.incompatible_type.total_count_change));
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
case RCL_PUBLISHER_MATCHED: {
|
|
161
|
+
obj.Set("total_count",
|
|
162
|
+
Napi::Number::New(env, data.publisher_matched.total_count));
|
|
163
|
+
obj.Set(
|
|
164
|
+
"total_count_change",
|
|
165
|
+
Napi::Number::New(env, data.publisher_matched.total_count_change));
|
|
166
|
+
obj.Set("current_count",
|
|
167
|
+
Napi::Number::New(env, data.publisher_matched.current_count));
|
|
168
|
+
obj.Set(
|
|
169
|
+
"current_count_change",
|
|
170
|
+
Napi::Number::New(env, data.publisher_matched.current_count_change));
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
default:
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
return obj;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
} // namespace
|
|
180
|
+
|
|
181
|
+
namespace rclnodejs {
|
|
182
|
+
|
|
183
|
+
Napi::Value CreateSubscriptionEventHandle(const Napi::CallbackInfo& info) {
|
|
184
|
+
Napi::Env env = info.Env();
|
|
185
|
+
RclHandle* subscription_handle =
|
|
186
|
+
RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
187
|
+
rcl_subscription_t* subscription =
|
|
188
|
+
reinterpret_cast<rcl_subscription_t*>(subscription_handle->ptr());
|
|
189
|
+
rcl_subscription_event_type_t event_type =
|
|
190
|
+
static_cast<rcl_subscription_event_type_t>(
|
|
191
|
+
info[1].As<Napi::Number>().Int32Value());
|
|
192
|
+
|
|
193
|
+
rcl_event_t* event = CreateEventHandle();
|
|
194
|
+
rcl_ret_t ret = rcl_subscription_event_init(event, subscription, event_type);
|
|
195
|
+
|
|
196
|
+
if (ret != RCL_RET_OK) {
|
|
197
|
+
Napi::Error::New(env, "failed to create subscription event")
|
|
198
|
+
.ThrowAsJavaScriptException();
|
|
199
|
+
rcl_reset_error();
|
|
200
|
+
free(event);
|
|
201
|
+
return env.Undefined();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
auto js_obj = RclHandle::NewInstance(env, event, nullptr, [env](void* ptr) {
|
|
205
|
+
rcl_event_t* event = reinterpret_cast<rcl_event_t*>(ptr);
|
|
206
|
+
rcl_ret_t ret = rcl_event_fini(event);
|
|
207
|
+
if (ret != RCL_RET_OK) {
|
|
208
|
+
Napi::Error::New(env, rcl_get_error_string().str)
|
|
209
|
+
.ThrowAsJavaScriptException();
|
|
210
|
+
rcl_reset_error();
|
|
211
|
+
}
|
|
212
|
+
free(ptr);
|
|
213
|
+
});
|
|
214
|
+
return js_obj;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
Napi::Value CreatePublisherEventHandle(const Napi::CallbackInfo& info) {
|
|
218
|
+
Napi::Env env = info.Env();
|
|
219
|
+
RclHandle* publisher_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
220
|
+
rcl_publisher_t* publisher =
|
|
221
|
+
reinterpret_cast<rcl_publisher_t*>(publisher_handle->ptr());
|
|
222
|
+
rcl_publisher_event_type_t event_type =
|
|
223
|
+
static_cast<rcl_publisher_event_type_t>(
|
|
224
|
+
info[1].As<Napi::Number>().Int32Value());
|
|
225
|
+
|
|
226
|
+
rcl_event_t* event = CreateEventHandle();
|
|
227
|
+
rcl_ret_t ret = rcl_publisher_event_init(event, publisher, event_type);
|
|
228
|
+
|
|
229
|
+
if (ret != RCL_RET_OK) {
|
|
230
|
+
Napi::Error::New(env, "failed to create publisher event")
|
|
231
|
+
.ThrowAsJavaScriptException();
|
|
232
|
+
rcl_reset_error();
|
|
233
|
+
free(event);
|
|
234
|
+
return env.Undefined();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
auto js_obj = RclHandle::NewInstance(env, event, nullptr, [env](void* ptr) {
|
|
238
|
+
rcl_event_t* event = reinterpret_cast<rcl_event_t*>(ptr);
|
|
239
|
+
rcl_ret_t ret = rcl_event_fini(event);
|
|
240
|
+
if (ret != RCL_RET_OK) {
|
|
241
|
+
Napi::Error::New(env, rcl_get_error_string().str)
|
|
242
|
+
.ThrowAsJavaScriptException();
|
|
243
|
+
rcl_reset_error();
|
|
244
|
+
}
|
|
245
|
+
free(ptr);
|
|
246
|
+
});
|
|
247
|
+
return js_obj;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
Napi::Value TakeEvent(const Napi::CallbackInfo& info) {
|
|
251
|
+
Napi::Env env = info.Env();
|
|
252
|
+
RclHandle* event_handle = RclHandle::Unwrap(info[0].As<Napi::Object>());
|
|
253
|
+
rcl_event_t* event = reinterpret_cast<rcl_event_t*>(event_handle->ptr());
|
|
254
|
+
auto event_type = info[1].As<Napi::Object>();
|
|
255
|
+
|
|
256
|
+
event_callback_data_t data;
|
|
257
|
+
rcl_ret_t ret;
|
|
258
|
+
if (event_type.Has("subscription_event_type")) {
|
|
259
|
+
rcl_subscription_event_type_t subscription_event_type =
|
|
260
|
+
static_cast<rcl_subscription_event_type_t>(
|
|
261
|
+
event_type.Get("subscription_event_type")
|
|
262
|
+
.As<Napi::Number>()
|
|
263
|
+
.Int32Value());
|
|
264
|
+
ret = rcl_take_event(event, &data);
|
|
265
|
+
if (RCL_RET_OK == ret) {
|
|
266
|
+
return CreateJSObjectForSubscriptionEvent(env, subscription_event_type,
|
|
267
|
+
data);
|
|
268
|
+
}
|
|
269
|
+
} else if (event_type.Has("publisher_event_type")) {
|
|
270
|
+
rcl_publisher_event_type_t publisher_event_type =
|
|
271
|
+
static_cast<rcl_publisher_event_type_t>(
|
|
272
|
+
event_type.Get("publisher_event_type")
|
|
273
|
+
.As<Napi::Number>()
|
|
274
|
+
.Int32Value());
|
|
275
|
+
ret = rcl_take_event(event, &data);
|
|
276
|
+
if (RCL_RET_OK == ret) {
|
|
277
|
+
return CreateJSObjectForPublisherEvent(env, publisher_event_type, data);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
Napi::Error::New(env, "failed to take event").ThrowAsJavaScriptException();
|
|
282
|
+
return env.Undefined();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
Napi::Object InitEventHandleBindings(Napi::Env env, Napi::Object exports) {
|
|
286
|
+
exports.Set("createSubscriptionEventHandle",
|
|
287
|
+
Napi::Function::New(env, CreateSubscriptionEventHandle));
|
|
288
|
+
exports.Set("createPublisherEventHandle",
|
|
289
|
+
Napi::Function::New(env, CreatePublisherEventHandle));
|
|
290
|
+
exports.Set("takeEvent", Napi::Function::New(env, TakeEvent));
|
|
291
|
+
return exports;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
} // 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_EVENT_HANDLE_BINDINGS_H_
|
|
16
|
+
#define SRC_RCL_EVENT_HANDLE_BINDINGS_H_
|
|
17
|
+
|
|
18
|
+
#include <napi.h>
|
|
19
|
+
|
|
20
|
+
namespace rclnodejs {
|
|
21
|
+
|
|
22
|
+
Napi::Object InitEventHandleBindings(Napi::Env env, Napi::Object exports);
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#endif // SRC_RCL_EVENT_HANDLE_BINDINGS_H_
|
|
@@ -41,11 +41,12 @@ Napi::Value CreateGuardCondition(const Napi::CallbackInfo& info) {
|
|
|
41
41
|
rcl_guard_condition_init(gc, context, gc_options),
|
|
42
42
|
rcl_get_error_string().str);
|
|
43
43
|
|
|
44
|
-
auto handle = RclHandle::NewInstance(env, gc, nullptr, [](void* ptr) {
|
|
44
|
+
auto handle = RclHandle::NewInstance(env, gc, nullptr, [env](void* ptr) {
|
|
45
45
|
rcl_guard_condition_t* gc = reinterpret_cast<rcl_guard_condition_t*>(ptr);
|
|
46
46
|
rcl_ret_t ret = rcl_guard_condition_fini(gc);
|
|
47
47
|
free(ptr);
|
|
48
|
-
|
|
48
|
+
THROW_ERROR_IF_NOT_EQUAL_NO_RETURN(RCL_RET_OK, ret,
|
|
49
|
+
rcl_get_error_string().str);
|
|
49
50
|
});
|
|
50
51
|
|
|
51
52
|
return handle;
|