rclnodejs 1.6.0 → 1.8.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/binding.gyp +2 -0
- package/index.js +152 -0
- package/lib/action/client.js +109 -10
- package/lib/action/deferred.js +8 -2
- package/lib/action/server.js +10 -1
- package/lib/action/uuid.js +4 -1
- package/lib/client.js +218 -4
- package/lib/clock.js +182 -1
- package/lib/clock_change.js +49 -0
- package/lib/clock_event.js +88 -0
- package/lib/context.js +12 -2
- package/lib/duration.js +37 -12
- package/lib/errors.js +621 -0
- package/lib/event_handler.js +21 -4
- package/lib/interface_loader.js +52 -12
- package/lib/lifecycle.js +8 -2
- package/lib/logging.js +90 -3
- package/lib/message_introspector.js +123 -0
- package/lib/message_serialization.js +10 -2
- package/lib/message_validation.js +512 -0
- package/lib/native_loader.js +9 -4
- package/lib/node.js +403 -50
- package/lib/node_options.js +40 -1
- package/lib/observable_subscription.js +105 -0
- package/lib/parameter.js +172 -35
- package/lib/parameter_client.js +506 -0
- package/lib/parameter_watcher.js +309 -0
- package/lib/publisher.js +56 -1
- package/lib/qos.js +79 -5
- package/lib/rate.js +6 -1
- package/lib/serialization.js +7 -2
- package/lib/subscription.js +8 -0
- package/lib/time.js +136 -21
- package/lib/time_source.js +13 -4
- package/lib/timer.js +42 -0
- package/lib/utils.js +27 -1
- package/lib/validator.js +74 -19
- package/package.json +4 -2
- package/prebuilds/linux-arm64/humble-jammy-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-arm64/jazzy-noble-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-arm64/kilted-noble-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/humble-jammy-x64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/jazzy-noble-x64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/kilted-noble-x64-rclnodejs.node +0 -0
- package/rosidl_gen/message_translator.js +0 -61
- package/scripts/config.js +1 -0
- package/src/addon.cpp +2 -0
- package/src/clock_event.cpp +268 -0
- package/src/clock_event.hpp +62 -0
- package/src/macros.h +2 -4
- package/src/rcl_action_server_bindings.cpp +21 -3
- package/src/rcl_bindings.cpp +59 -0
- package/src/rcl_context_bindings.cpp +5 -0
- package/src/rcl_graph_bindings.cpp +73 -0
- package/src/rcl_logging_bindings.cpp +158 -0
- package/src/rcl_node_bindings.cpp +14 -2
- package/src/rcl_publisher_bindings.cpp +12 -0
- package/src/rcl_service_bindings.cpp +7 -6
- package/src/rcl_subscription_bindings.cpp +51 -14
- package/src/rcl_time_point_bindings.cpp +135 -0
- package/src/rcl_timer_bindings.cpp +140 -0
- package/src/rcl_utilities.cpp +103 -2
- package/src/rcl_utilities.h +7 -1
- package/types/action_client.d.ts +27 -2
- package/types/base.d.ts +6 -0
- package/types/client.d.ts +65 -1
- package/types/clock.d.ts +86 -0
- package/types/clock_change.d.ts +27 -0
- package/types/clock_event.d.ts +51 -0
- package/types/errors.d.ts +496 -0
- package/types/index.d.ts +10 -0
- package/types/logging.d.ts +32 -0
- package/types/message_introspector.d.ts +75 -0
- package/types/message_validation.d.ts +183 -0
- package/types/node.d.ts +107 -0
- package/types/node_options.d.ts +13 -0
- package/types/observable_subscription.d.ts +39 -0
- package/types/parameter_client.d.ts +252 -0
- package/types/parameter_watcher.d.ts +104 -0
- package/types/publisher.d.ts +28 -1
- package/types/qos.d.ts +18 -0
- package/types/subscription.d.ts +6 -0
- package/types/timer.d.ts +18 -0
- package/types/validator.d.ts +86 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
// Copyright (c) 2025 Mahmoud Alghalayini. All rights reserved.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const EventEmitter = require('events');
|
|
18
|
+
const { TypeValidationError, OperationError } = require('./errors');
|
|
19
|
+
const { normalizeNodeName } = require('./utils');
|
|
20
|
+
const debug = require('debug')('rclnodejs:parameter_watcher');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @class ParameterWatcher - Watches parameter changes on a remote node
|
|
24
|
+
*
|
|
25
|
+
* Subscribes to /parameter_events and emits 'change' events when
|
|
26
|
+
* watched parameters on the target node are modified.
|
|
27
|
+
*
|
|
28
|
+
* @extends EventEmitter
|
|
29
|
+
*/
|
|
30
|
+
class ParameterWatcher extends EventEmitter {
|
|
31
|
+
#node;
|
|
32
|
+
#paramClient;
|
|
33
|
+
#subscription;
|
|
34
|
+
#watchedParams;
|
|
35
|
+
#remoteNodeName;
|
|
36
|
+
#destroyed;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create a ParameterWatcher instance.
|
|
40
|
+
* Note: Use node.createParameterWatcher() instead of calling this directly.
|
|
41
|
+
*
|
|
42
|
+
* @param {object} node - The local rclnodejs Node instance
|
|
43
|
+
* @param {string} remoteNodeName - Name of the remote node to watch
|
|
44
|
+
* @param {string[]} parameterNames - Array of parameter names to watch
|
|
45
|
+
* @param {object} [options] - Options for the parameter client
|
|
46
|
+
* @param {number} [options.timeout=5000] - Default timeout for parameter operations
|
|
47
|
+
* @hideconstructor
|
|
48
|
+
*/
|
|
49
|
+
constructor(node, remoteNodeName, parameterNames, options = {}) {
|
|
50
|
+
super();
|
|
51
|
+
|
|
52
|
+
if (!node || typeof node.createParameterClient !== 'function') {
|
|
53
|
+
throw new TypeValidationError('node', node, 'Node instance', {
|
|
54
|
+
entityType: 'parameter watcher',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (typeof remoteNodeName !== 'string' || remoteNodeName.trim() === '') {
|
|
59
|
+
throw new TypeValidationError(
|
|
60
|
+
'remoteNodeName',
|
|
61
|
+
remoteNodeName,
|
|
62
|
+
'non-empty string',
|
|
63
|
+
{
|
|
64
|
+
entityType: 'parameter watcher',
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!Array.isArray(parameterNames) || parameterNames.length === 0) {
|
|
70
|
+
throw new TypeValidationError(
|
|
71
|
+
'parameterNames',
|
|
72
|
+
parameterNames,
|
|
73
|
+
'non-empty array',
|
|
74
|
+
{
|
|
75
|
+
entityType: 'parameter watcher',
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
this.#node = node;
|
|
81
|
+
this.#watchedParams = new Set(parameterNames);
|
|
82
|
+
this.#paramClient = node.createParameterClient(remoteNodeName, options);
|
|
83
|
+
// Cache the remote node name for error messages (in case paramClient is destroyed)
|
|
84
|
+
this.#remoteNodeName = this.#paramClient.remoteNodeName;
|
|
85
|
+
this.#subscription = null;
|
|
86
|
+
this.#destroyed = false;
|
|
87
|
+
|
|
88
|
+
debug(
|
|
89
|
+
'Created ParameterWatcher for node=%s, params=%o',
|
|
90
|
+
remoteNodeName,
|
|
91
|
+
parameterNames
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get the remote node name being watched.
|
|
97
|
+
* @type {string}
|
|
98
|
+
* @readonly
|
|
99
|
+
*/
|
|
100
|
+
get remoteNodeName() {
|
|
101
|
+
return this.#remoteNodeName;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get the list of watched parameter names.
|
|
106
|
+
* @type {string[]}
|
|
107
|
+
* @readonly
|
|
108
|
+
*/
|
|
109
|
+
get watchedParameters() {
|
|
110
|
+
return Array.from(this.#watchedParams);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Start watching for parameter changes.
|
|
115
|
+
* Waits for the remote node's parameter services and subscribes to parameter events.
|
|
116
|
+
*
|
|
117
|
+
* @param {number} [timeout=5000] - Timeout in milliseconds to wait for services
|
|
118
|
+
* @returns {Promise<boolean>} Resolves to true when watching has started
|
|
119
|
+
* @throws {Error} If the watcher has been destroyed
|
|
120
|
+
*/
|
|
121
|
+
async start(timeout = 5000) {
|
|
122
|
+
this.#checkNotDestroyed();
|
|
123
|
+
|
|
124
|
+
debug('Starting ParameterWatcher for node=%s', this.remoteNodeName);
|
|
125
|
+
|
|
126
|
+
const available = await this.#paramClient.waitForService(timeout);
|
|
127
|
+
|
|
128
|
+
if (!available) {
|
|
129
|
+
debug(
|
|
130
|
+
'Parameter services not available for node=%s',
|
|
131
|
+
this.remoteNodeName
|
|
132
|
+
);
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!this.#subscription) {
|
|
137
|
+
this.#subscription = this.#node.createSubscription(
|
|
138
|
+
'rcl_interfaces/msg/ParameterEvent',
|
|
139
|
+
'/parameter_events',
|
|
140
|
+
(event) => this.#handleParameterEvent(event)
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
debug('Subscribed to /parameter_events');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get current values of all watched parameters.
|
|
151
|
+
*
|
|
152
|
+
* @param {object} [options] - Options for the parameter client
|
|
153
|
+
* @param {number} [options.timeout] - Timeout in milliseconds
|
|
154
|
+
* @param {AbortSignal} [options.signal] - AbortSignal for cancellation
|
|
155
|
+
* @returns {Promise<Parameter[]>} Array of Parameter objects
|
|
156
|
+
* @throws {Error} If the watcher has been destroyed
|
|
157
|
+
*/
|
|
158
|
+
async getCurrentValues(options) {
|
|
159
|
+
this.#checkNotDestroyed();
|
|
160
|
+
return await this.#paramClient.getParameters(
|
|
161
|
+
Array.from(this.#watchedParams),
|
|
162
|
+
options
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Add a parameter name to the watch list.
|
|
168
|
+
*
|
|
169
|
+
* @param {string} name - Parameter name to watch
|
|
170
|
+
* @throws {TypeError} If name is not a string
|
|
171
|
+
* @throws {Error} If the watcher has been destroyed
|
|
172
|
+
*/
|
|
173
|
+
addParameter(name) {
|
|
174
|
+
this.#checkNotDestroyed();
|
|
175
|
+
|
|
176
|
+
if (typeof name !== 'string' || name.trim() === '') {
|
|
177
|
+
throw new TypeValidationError('name', name, 'non-empty string', {
|
|
178
|
+
entityType: 'parameter watcher',
|
|
179
|
+
entityName: this.remoteNodeName,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const wasAdded = !this.#watchedParams.has(name);
|
|
184
|
+
this.#watchedParams.add(name);
|
|
185
|
+
|
|
186
|
+
if (wasAdded) {
|
|
187
|
+
debug('Added parameter to watch list: %s', name);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Remove a parameter name from the watch list.
|
|
193
|
+
*
|
|
194
|
+
* @param {string} name - Parameter name to stop watching
|
|
195
|
+
* @returns {boolean} True if the parameter was in the watch list
|
|
196
|
+
* @throws {Error} If the watcher has been destroyed
|
|
197
|
+
*/
|
|
198
|
+
removeParameter(name) {
|
|
199
|
+
this.#checkNotDestroyed();
|
|
200
|
+
|
|
201
|
+
const wasRemoved = this.#watchedParams.delete(name);
|
|
202
|
+
|
|
203
|
+
if (wasRemoved) {
|
|
204
|
+
debug('Removed parameter from watch list: %s', name);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return wasRemoved;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Check if the watcher has been destroyed.
|
|
212
|
+
*
|
|
213
|
+
* @returns {boolean} True if destroyed
|
|
214
|
+
*/
|
|
215
|
+
isDestroyed() {
|
|
216
|
+
return this.#destroyed;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Destroy the watcher and clean up resources.
|
|
221
|
+
* Unsubscribes from parameter events and destroys the parameter client.
|
|
222
|
+
*/
|
|
223
|
+
destroy() {
|
|
224
|
+
if (this.#destroyed) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
debug('Destroying ParameterWatcher for node=%s', this.remoteNodeName);
|
|
229
|
+
|
|
230
|
+
if (this.#subscription) {
|
|
231
|
+
try {
|
|
232
|
+
this.#node.destroySubscription(this.#subscription);
|
|
233
|
+
} catch (error) {
|
|
234
|
+
debug('Error destroying subscription: %s', error.message);
|
|
235
|
+
}
|
|
236
|
+
this.#subscription = null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (this.#paramClient) {
|
|
240
|
+
try {
|
|
241
|
+
this.#node.destroyParameterClient(this.#paramClient);
|
|
242
|
+
} catch (error) {
|
|
243
|
+
debug('Error destroying parameter client: %s', error.message);
|
|
244
|
+
}
|
|
245
|
+
this.#paramClient = null;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
this.removeAllListeners();
|
|
249
|
+
|
|
250
|
+
this.#destroyed = true;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Handle parameter event from /parameter_events topic.
|
|
255
|
+
* @private
|
|
256
|
+
*/
|
|
257
|
+
#handleParameterEvent(event) {
|
|
258
|
+
if (normalizeNodeName(event.node) !== this.remoteNodeName) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const relevantChanges = [];
|
|
263
|
+
|
|
264
|
+
if (event.new_parameters) {
|
|
265
|
+
const newParams = event.new_parameters.filter((p) =>
|
|
266
|
+
this.#watchedParams.has(p.name)
|
|
267
|
+
);
|
|
268
|
+
relevantChanges.push(...newParams);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (event.changed_parameters) {
|
|
272
|
+
const changedParams = event.changed_parameters.filter((p) =>
|
|
273
|
+
this.#watchedParams.has(p.name)
|
|
274
|
+
);
|
|
275
|
+
relevantChanges.push(...changedParams);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (event.deleted_parameters) {
|
|
279
|
+
const deletedParams = event.deleted_parameters.filter((p) =>
|
|
280
|
+
this.#watchedParams.has(p.name)
|
|
281
|
+
);
|
|
282
|
+
relevantChanges.push(...deletedParams);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (relevantChanges.length > 0) {
|
|
286
|
+
debug(
|
|
287
|
+
'Parameter change detected: %o',
|
|
288
|
+
relevantChanges.map((p) => p.name)
|
|
289
|
+
);
|
|
290
|
+
this.emit('change', relevantChanges);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Check if the watcher has been destroyed and throw if so.
|
|
296
|
+
* @private
|
|
297
|
+
*/
|
|
298
|
+
#checkNotDestroyed() {
|
|
299
|
+
if (this.#destroyed) {
|
|
300
|
+
throw new OperationError('ParameterWatcher has been destroyed', {
|
|
301
|
+
code: 'WATCHER_DESTROYED',
|
|
302
|
+
entityType: 'parameter watcher',
|
|
303
|
+
entityName: this.remoteNodeName,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
module.exports = ParameterWatcher;
|
package/lib/publisher.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
const rclnodejs = require('./native_loader.js');
|
|
18
18
|
const debug = require('debug')('rclnodejs:publisher');
|
|
19
19
|
const Entity = require('./entity.js');
|
|
20
|
+
const { assertValidMessage } = require('./message_validation.js');
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* @class - Class representing a Publisher in ROS
|
|
@@ -27,6 +28,11 @@ class Publisher extends Entity {
|
|
|
27
28
|
constructor(handle, typeClass, topic, options, node, eventCallbacks) {
|
|
28
29
|
super(handle, typeClass, options);
|
|
29
30
|
this._node = node;
|
|
31
|
+
this._validateMessages = options.validateMessages || false;
|
|
32
|
+
this._validationOptions = options.validationOptions || {
|
|
33
|
+
strict: true,
|
|
34
|
+
checkTypes: true,
|
|
35
|
+
};
|
|
30
36
|
if (node && eventCallbacks) {
|
|
31
37
|
this._events = eventCallbacks.createEventHandlers(this.handle);
|
|
32
38
|
node._events.push(...this._events);
|
|
@@ -44,12 +50,24 @@ class Publisher extends Entity {
|
|
|
44
50
|
* Publish a message
|
|
45
51
|
* @param {object|Buffer} message - The message to be sent, could be kind of JavaScript message generated from .msg
|
|
46
52
|
* or be a Buffer for a raw message.
|
|
53
|
+
* @param {object} [options] - Publish options
|
|
54
|
+
* @param {boolean} [options.validate] - Override validateMessages setting for this publish call
|
|
47
55
|
* @return {undefined}
|
|
56
|
+
* @throws {MessageValidationError} If validation is enabled and message is invalid
|
|
48
57
|
*/
|
|
49
|
-
publish(message) {
|
|
58
|
+
publish(message, options = {}) {
|
|
50
59
|
if (message instanceof Buffer) {
|
|
51
60
|
rclnodejs.publishRawMessage(this._handle, message);
|
|
52
61
|
} else {
|
|
62
|
+
const shouldValidate =
|
|
63
|
+
options.validate !== undefined
|
|
64
|
+
? options.validate
|
|
65
|
+
: this._validateMessages;
|
|
66
|
+
|
|
67
|
+
if (shouldValidate && !(message instanceof this._typeClass)) {
|
|
68
|
+
assertValidMessage(message, this._typeClass, this._validationOptions);
|
|
69
|
+
}
|
|
70
|
+
|
|
53
71
|
// Enables call by plain object/number/string argument
|
|
54
72
|
// e.g. publisher.publish(3.14);
|
|
55
73
|
// publisher.publish('The quick brown fox...');
|
|
@@ -65,6 +83,35 @@ class Publisher extends Entity {
|
|
|
65
83
|
debug(`Message of topic ${this.topic} has been published.`);
|
|
66
84
|
}
|
|
67
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Whether messages will be validated before publishing.
|
|
88
|
+
* @type {boolean}
|
|
89
|
+
*/
|
|
90
|
+
get willValidateMessage() {
|
|
91
|
+
return this._validateMessages;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Enable or disable message validation for this publisher.
|
|
96
|
+
* @param {boolean} value - Whether to validate messages before publishing
|
|
97
|
+
*/
|
|
98
|
+
set willValidateMessage(value) {
|
|
99
|
+
this._validateMessages = value;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Set validation options for this publisher.
|
|
104
|
+
* @param {object} options - Validation options
|
|
105
|
+
* @param {boolean} [options.strict=true] - Throw on unknown fields
|
|
106
|
+
* @param {boolean} [options.checkTypes=true] - Validate field types
|
|
107
|
+
* @param {boolean} [options.checkRequired=false] - Check for missing fields
|
|
108
|
+
*/
|
|
109
|
+
setValidation(options) {
|
|
110
|
+
if (options && Object.keys(options).length > 0) {
|
|
111
|
+
this._validationOptions = { ...this._validationOptions, ...options };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
68
115
|
static createPublisher(node, typeClass, topic, options, eventCallbacks) {
|
|
69
116
|
let type = typeClass.type();
|
|
70
117
|
let handle = rclnodejs.createPublisher(
|
|
@@ -112,6 +159,14 @@ class Publisher extends Entity {
|
|
|
112
159
|
return rclnodejs.waitForAllAcked(this._handle, timeout);
|
|
113
160
|
}
|
|
114
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Manually assert that this Publisher is alive (for RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC).
|
|
164
|
+
* @return {undefined}
|
|
165
|
+
*/
|
|
166
|
+
assertLiveliness() {
|
|
167
|
+
rclnodejs.assertLiveliness(this._handle);
|
|
168
|
+
}
|
|
169
|
+
|
|
115
170
|
/**
|
|
116
171
|
* Get the event handlers for this publisher.
|
|
117
172
|
* @returns {Array} The array of event handlers for this publisher.
|
package/lib/qos.js
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
|
+
const { TypeValidationError } = require('./errors.js');
|
|
18
|
+
|
|
17
19
|
/**
|
|
18
20
|
* Enum for HistoryPolicy
|
|
19
21
|
* @readonly
|
|
@@ -56,6 +58,24 @@ let DurabilityPolicy = {
|
|
|
56
58
|
RMW_QOS_POLICY_DURABILITY_VOLATILE: 2,
|
|
57
59
|
};
|
|
58
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Enum for LivelinessPolicy
|
|
63
|
+
* @readonly
|
|
64
|
+
* @enum {number}
|
|
65
|
+
*/
|
|
66
|
+
let LivelinessPolicy = {
|
|
67
|
+
/** @member {number} */
|
|
68
|
+
RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT: 0,
|
|
69
|
+
/** @member {number} */
|
|
70
|
+
RMW_QOS_POLICY_LIVELINESS_AUTOMATIC: 1,
|
|
71
|
+
/** @member {number} */
|
|
72
|
+
RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC: 3,
|
|
73
|
+
/** @member {number} */
|
|
74
|
+
RMW_QOS_POLICY_LIVELINESS_UNKNOWN: 4,
|
|
75
|
+
/** @member {number} */
|
|
76
|
+
RMW_QOS_POLICY_LIVELINESS_BEST_AVAILABLE: 5,
|
|
77
|
+
};
|
|
78
|
+
|
|
59
79
|
/** Class representing middleware quality of service */
|
|
60
80
|
class QoS {
|
|
61
81
|
/**
|
|
@@ -71,12 +91,14 @@ class QoS {
|
|
|
71
91
|
depth = 0,
|
|
72
92
|
reliability = ReliabilityPolicy.RMW_QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT,
|
|
73
93
|
durability = DurabilityPolicy.RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT,
|
|
94
|
+
liveliness = LivelinessPolicy.RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT,
|
|
74
95
|
avoidRosNameSpaceConventions = false
|
|
75
96
|
) {
|
|
76
97
|
this._history = history;
|
|
77
98
|
this._depth = depth;
|
|
78
99
|
this._reliability = reliability;
|
|
79
100
|
this._durability = durability;
|
|
101
|
+
this._liveliness = liveliness;
|
|
80
102
|
this._avoidRosNameSpaceConventions = avoidRosNameSpaceConventions;
|
|
81
103
|
}
|
|
82
104
|
|
|
@@ -110,6 +132,16 @@ class QoS {
|
|
|
110
132
|
return DurabilityPolicy;
|
|
111
133
|
}
|
|
112
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Get LivelinessPolicy enum.
|
|
137
|
+
* @name QoS#static get:LivelinessPolicy
|
|
138
|
+
* @function
|
|
139
|
+
* @return {LivelinessPolicy}
|
|
140
|
+
*/
|
|
141
|
+
static get LivelinessPolicy() {
|
|
142
|
+
return LivelinessPolicy;
|
|
143
|
+
}
|
|
144
|
+
|
|
113
145
|
/**
|
|
114
146
|
* Get the history value.
|
|
115
147
|
* @name QoS#get:history
|
|
@@ -129,7 +161,9 @@ class QoS {
|
|
|
129
161
|
*/
|
|
130
162
|
set history(history) {
|
|
131
163
|
if (typeof history !== 'number') {
|
|
132
|
-
throw new
|
|
164
|
+
throw new TypeValidationError('history', history, 'number', {
|
|
165
|
+
entityType: 'qos',
|
|
166
|
+
});
|
|
133
167
|
}
|
|
134
168
|
|
|
135
169
|
this._history = history;
|
|
@@ -154,7 +188,9 @@ class QoS {
|
|
|
154
188
|
*/
|
|
155
189
|
set depth(depth) {
|
|
156
190
|
if (typeof depth !== 'number') {
|
|
157
|
-
throw new
|
|
191
|
+
throw new TypeValidationError('depth', depth, 'number', {
|
|
192
|
+
entityType: 'qos',
|
|
193
|
+
});
|
|
158
194
|
}
|
|
159
195
|
|
|
160
196
|
this._depth = depth;
|
|
@@ -179,7 +215,9 @@ class QoS {
|
|
|
179
215
|
*/
|
|
180
216
|
set reliability(reliability) {
|
|
181
217
|
if (typeof reliability !== 'number') {
|
|
182
|
-
throw new
|
|
218
|
+
throw new TypeValidationError('reliability', reliability, 'number', {
|
|
219
|
+
entityType: 'qos',
|
|
220
|
+
});
|
|
183
221
|
}
|
|
184
222
|
|
|
185
223
|
this._reliability = reliability;
|
|
@@ -204,12 +242,41 @@ class QoS {
|
|
|
204
242
|
*/
|
|
205
243
|
set durability(durability) {
|
|
206
244
|
if (typeof durability !== 'number') {
|
|
207
|
-
throw new
|
|
245
|
+
throw new TypeValidationError('durability', durability, 'number', {
|
|
246
|
+
entityType: 'qos',
|
|
247
|
+
});
|
|
208
248
|
}
|
|
209
249
|
|
|
210
250
|
this._durability = durability;
|
|
211
251
|
}
|
|
212
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Get the liveliness value.
|
|
255
|
+
* @name QoS#get:liveliness
|
|
256
|
+
* @function
|
|
257
|
+
* @return {number}
|
|
258
|
+
*/
|
|
259
|
+
get liveliness() {
|
|
260
|
+
return this._liveliness;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Set the liveliness value.
|
|
265
|
+
* @param {number} liveliness - value to be set.
|
|
266
|
+
* @name QoS#set:liveliness
|
|
267
|
+
* @function
|
|
268
|
+
* @return {undefined}
|
|
269
|
+
*/
|
|
270
|
+
set liveliness(liveliness) {
|
|
271
|
+
if (typeof liveliness !== 'number') {
|
|
272
|
+
throw new TypeValidationError('liveliness', liveliness, 'number', {
|
|
273
|
+
entityType: 'qos',
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
this._liveliness = liveliness;
|
|
278
|
+
}
|
|
279
|
+
|
|
213
280
|
/**
|
|
214
281
|
* Get the avoidRosNameSpaceConventions value.
|
|
215
282
|
* @name QoS#get:avoidRosNameSpaceConventions
|
|
@@ -229,7 +296,14 @@ class QoS {
|
|
|
229
296
|
*/
|
|
230
297
|
set avoidRosNameSpaceConventions(avoidRosNameSpaceConventions) {
|
|
231
298
|
if (typeof avoidRosNameSpaceConventions !== 'boolean') {
|
|
232
|
-
throw new
|
|
299
|
+
throw new TypeValidationError(
|
|
300
|
+
'avoidRosNameSpaceConventions',
|
|
301
|
+
avoidRosNameSpaceConventions,
|
|
302
|
+
'boolean',
|
|
303
|
+
{
|
|
304
|
+
entityType: 'qos',
|
|
305
|
+
}
|
|
306
|
+
);
|
|
233
307
|
}
|
|
234
308
|
|
|
235
309
|
this._avoidRosNameSpaceConventions = avoidRosNameSpaceConventions;
|
package/lib/rate.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
const rclnodejs = require('../index.js');
|
|
16
16
|
const Context = require('./context.js');
|
|
17
17
|
const NodeOptions = require('./node_options.js');
|
|
18
|
+
const { OperationError } = require('./errors.js');
|
|
18
19
|
|
|
19
20
|
const NOP_FN = () => {};
|
|
20
21
|
|
|
@@ -86,7 +87,11 @@ class Rate {
|
|
|
86
87
|
*/
|
|
87
88
|
async sleep() {
|
|
88
89
|
if (this.isCanceled()) {
|
|
89
|
-
throw new
|
|
90
|
+
throw new OperationError('Rate has been cancelled', {
|
|
91
|
+
code: 'RATE_CANCELLED',
|
|
92
|
+
entityType: 'rate',
|
|
93
|
+
details: { frequency: this._hz },
|
|
94
|
+
});
|
|
90
95
|
}
|
|
91
96
|
|
|
92
97
|
return new Promise((resolve) => {
|
package/lib/serialization.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
17
|
const rclnodejs = require('./native_loader.js');
|
|
18
|
+
const { TypeValidationError } = require('./errors.js');
|
|
18
19
|
|
|
19
20
|
class Serialization {
|
|
20
21
|
/**
|
|
@@ -25,7 +26,9 @@ class Serialization {
|
|
|
25
26
|
*/
|
|
26
27
|
static serializeMessage(message, typeClass) {
|
|
27
28
|
if (!(message instanceof typeClass)) {
|
|
28
|
-
throw new
|
|
29
|
+
throw new TypeValidationError('message', message, typeClass.name, {
|
|
30
|
+
entityType: 'serializer',
|
|
31
|
+
});
|
|
29
32
|
}
|
|
30
33
|
return rclnodejs.serialize(
|
|
31
34
|
typeClass.type().pkgName,
|
|
@@ -43,7 +46,9 @@ class Serialization {
|
|
|
43
46
|
*/
|
|
44
47
|
static deserializeMessage(buffer, typeClass) {
|
|
45
48
|
if (!(buffer instanceof Buffer)) {
|
|
46
|
-
throw new
|
|
49
|
+
throw new TypeValidationError('buffer', buffer, 'Buffer', {
|
|
50
|
+
entityType: 'serializer',
|
|
51
|
+
});
|
|
47
52
|
}
|
|
48
53
|
const rosMsg = new typeClass();
|
|
49
54
|
rclnodejs.deserialize(
|
package/lib/subscription.js
CHANGED
|
@@ -151,6 +151,14 @@ class Subscription extends Entity {
|
|
|
151
151
|
: this.clearContentFilter();
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Get the current content-filter.
|
|
156
|
+
* @returns {object} - The content-filter description {expression: string, parameters: string[]} or undefined if not set/supported.
|
|
157
|
+
*/
|
|
158
|
+
getContentFilter() {
|
|
159
|
+
return rclnodejs.getContentFilter(this.handle);
|
|
160
|
+
}
|
|
161
|
+
|
|
154
162
|
/**
|
|
155
163
|
* Clear the current content-filter. No filtering is to be applied.
|
|
156
164
|
* @returns {boolean} - True if successful; false otherwise
|