rclnodejs 1.5.2 → 1.7.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/index.js +79 -3
- package/lib/action/client.js +55 -9
- 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 +152 -3
- package/lib/clock.js +4 -1
- package/lib/context.js +12 -2
- package/lib/duration.js +37 -12
- package/lib/errors.js +571 -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 +12 -3
- package/lib/message_serialization.js +179 -0
- package/lib/native_loader.js +9 -4
- package/lib/node.js +283 -47
- package/lib/parameter.js +176 -45
- package/lib/parameter_client.js +506 -0
- package/lib/parameter_watcher.js +309 -0
- package/lib/qos.js +22 -5
- package/lib/rate.js +6 -1
- package/lib/serialization.js +7 -2
- package/lib/subscription.js +16 -1
- package/lib/time.js +136 -21
- package/lib/time_source.js +13 -4
- package/lib/utils.js +313 -0
- package/lib/validator.js +11 -12
- package/package.json +2 -7
- 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_convertor/idl_convertor.js +3 -2
- package/rosidl_gen/generate_worker.js +1 -1
- package/rosidl_gen/idl_generator.js +11 -24
- package/rosidl_gen/index.js +1 -1
- package/rosidl_gen/templates/action-template.js +68 -0
- package/rosidl_gen/templates/message-template.js +1113 -0
- package/rosidl_gen/templates/service-event-template.js +31 -0
- package/rosidl_gen/templates/service-template.js +44 -0
- package/rosidl_parser/rosidl_parser.js +2 -2
- package/third_party/ref-napi/lib/ref.js +0 -45
- package/types/base.d.ts +3 -0
- package/types/client.d.ts +36 -0
- package/types/errors.d.ts +447 -0
- package/types/index.d.ts +17 -0
- package/types/interfaces.d.ts +1910 -1
- package/types/node.d.ts +56 -1
- package/types/parameter_client.d.ts +252 -0
- package/types/parameter_watcher.d.ts +104 -0
- package/rosidl_gen/templates/CMakeLists.dot +0 -40
- package/rosidl_gen/templates/action.dot +0 -50
- package/rosidl_gen/templates/message.dot +0 -851
- package/rosidl_gen/templates/package.dot +0 -16
- package/rosidl_gen/templates/service.dot +0 -26
- package/rosidl_gen/templates/service_event.dot +0 -10
package/lib/errors.js
ADDED
|
@@ -0,0 +1,571 @@
|
|
|
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
|
+
/**
|
|
18
|
+
* Base error class for all rclnodejs errors.
|
|
19
|
+
* Provides structured error information with context.
|
|
20
|
+
* @class
|
|
21
|
+
*/
|
|
22
|
+
class RclNodeError extends Error {
|
|
23
|
+
/**
|
|
24
|
+
* @param {string} message - Human-readable error message
|
|
25
|
+
* @param {object} [options] - Additional error context
|
|
26
|
+
* @param {string} [options.code] - Machine-readable error code (e.g., 'TIMEOUT', 'INVALID_ARGUMENT')
|
|
27
|
+
* @param {string} [options.nodeName] - Name of the node where error occurred
|
|
28
|
+
* @param {string} [options.entityType] - Type of entity (publisher, subscription, client, etc.)
|
|
29
|
+
* @param {string} [options.entityName] - Name of the entity (topic name, service name, etc.)
|
|
30
|
+
* @param {Error} [options.cause] - Original error that caused this error
|
|
31
|
+
* @param {any} [options.details] - Additional error-specific details
|
|
32
|
+
*/
|
|
33
|
+
constructor(message, options = {}) {
|
|
34
|
+
super(message);
|
|
35
|
+
|
|
36
|
+
// Maintains proper stack trace for where our error was thrown
|
|
37
|
+
Error.captureStackTrace(this, this.constructor);
|
|
38
|
+
|
|
39
|
+
this.name = this.constructor.name;
|
|
40
|
+
this.code = options.code || 'UNKNOWN_ERROR';
|
|
41
|
+
this.nodeName = options.nodeName;
|
|
42
|
+
this.entityType = options.entityType;
|
|
43
|
+
this.entityName = options.entityName;
|
|
44
|
+
this.details = options.details;
|
|
45
|
+
|
|
46
|
+
// Error chaining (ES2022 feature, Node.js 16.9+)
|
|
47
|
+
if (options.cause) {
|
|
48
|
+
this.cause = options.cause;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Timestamp for logging/debugging
|
|
52
|
+
this.timestamp = new Date();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Returns a detailed error object for logging/serialization
|
|
57
|
+
* @return {object} Structured error information
|
|
58
|
+
*/
|
|
59
|
+
toJSON() {
|
|
60
|
+
return {
|
|
61
|
+
name: this.name,
|
|
62
|
+
message: this.message,
|
|
63
|
+
code: this.code,
|
|
64
|
+
nodeName: this.nodeName,
|
|
65
|
+
entityType: this.entityType,
|
|
66
|
+
entityName: this.entityName,
|
|
67
|
+
details: this.details,
|
|
68
|
+
timestamp: this.timestamp.toISOString(),
|
|
69
|
+
stack: this.stack,
|
|
70
|
+
cause: this.cause
|
|
71
|
+
? this.cause.toJSON?.() || this.cause.message
|
|
72
|
+
: undefined,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Returns a user-friendly error description
|
|
78
|
+
* @return {string} Formatted error string
|
|
79
|
+
*/
|
|
80
|
+
toString() {
|
|
81
|
+
let str = `${this.name}: ${this.message}`;
|
|
82
|
+
if (this.code) str += ` [${this.code}]`;
|
|
83
|
+
if (this.nodeName) str += ` (node: ${this.nodeName})`;
|
|
84
|
+
if (this.entityName)
|
|
85
|
+
str += ` (${this.entityType || 'entity'}: ${this.entityName})`;
|
|
86
|
+
return str;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Error thrown when validation fails
|
|
92
|
+
* @class
|
|
93
|
+
* @extends RclNodeError
|
|
94
|
+
*/
|
|
95
|
+
class ValidationError extends RclNodeError {
|
|
96
|
+
/**
|
|
97
|
+
* @param {string} message - Error message
|
|
98
|
+
* @param {object} [options] - Additional options
|
|
99
|
+
* @param {string} [options.argumentName] - Name of the argument that failed validation
|
|
100
|
+
* @param {any} [options.providedValue] - The value that was provided
|
|
101
|
+
* @param {string} [options.expectedType] - The expected type or format
|
|
102
|
+
* @param {string} [options.validationRule] - The validation rule that failed
|
|
103
|
+
*/
|
|
104
|
+
constructor(message, options = {}) {
|
|
105
|
+
super(message, { code: 'VALIDATION_ERROR', ...options });
|
|
106
|
+
this.argumentName = options.argumentName;
|
|
107
|
+
this.providedValue = options.providedValue;
|
|
108
|
+
this.expectedType = options.expectedType;
|
|
109
|
+
this.validationRule = options.validationRule;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Type validation error
|
|
115
|
+
* @class
|
|
116
|
+
* @extends ValidationError
|
|
117
|
+
*/
|
|
118
|
+
class TypeValidationError extends ValidationError {
|
|
119
|
+
/**
|
|
120
|
+
* @param {string} argumentName - Name of the argument
|
|
121
|
+
* @param {any} providedValue - The value that was provided
|
|
122
|
+
* @param {string} expectedType - The expected type
|
|
123
|
+
* @param {object} [options] - Additional options
|
|
124
|
+
*/
|
|
125
|
+
constructor(argumentName, providedValue, expectedType, options = {}) {
|
|
126
|
+
super(
|
|
127
|
+
`Invalid type for '${argumentName}': expected ${expectedType}, got ${typeof providedValue}`,
|
|
128
|
+
{
|
|
129
|
+
code: 'INVALID_TYPE',
|
|
130
|
+
argumentName,
|
|
131
|
+
providedValue,
|
|
132
|
+
expectedType,
|
|
133
|
+
...options,
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Range/value validation error
|
|
141
|
+
* @class
|
|
142
|
+
* @extends ValidationError
|
|
143
|
+
*/
|
|
144
|
+
class RangeValidationError extends ValidationError {
|
|
145
|
+
/**
|
|
146
|
+
* @param {string} argumentName - Name of the argument
|
|
147
|
+
* @param {any} providedValue - The value that was provided
|
|
148
|
+
* @param {string} constraint - The constraint that was violated
|
|
149
|
+
* @param {object} [options] - Additional options
|
|
150
|
+
*/
|
|
151
|
+
constructor(argumentName, providedValue, constraint, options = {}) {
|
|
152
|
+
super(
|
|
153
|
+
`Value '${providedValue}' for '${argumentName}' is out of range: ${constraint}`,
|
|
154
|
+
{
|
|
155
|
+
code: 'OUT_OF_RANGE',
|
|
156
|
+
argumentName,
|
|
157
|
+
providedValue,
|
|
158
|
+
validationRule: constraint,
|
|
159
|
+
...options,
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* ROS name validation error (topics, nodes, services)
|
|
167
|
+
* @class
|
|
168
|
+
* @extends ValidationError
|
|
169
|
+
*/
|
|
170
|
+
class NameValidationError extends ValidationError {
|
|
171
|
+
/**
|
|
172
|
+
* @param {string} name - The invalid name
|
|
173
|
+
* @param {string} nameType - Type of name (node, topic, service, etc.)
|
|
174
|
+
* @param {string} validationResult - The validation error message
|
|
175
|
+
* @param {number} invalidIndex - Index where validation failed
|
|
176
|
+
* @param {object} [options] - Additional options
|
|
177
|
+
*/
|
|
178
|
+
constructor(name, nameType, validationResult, invalidIndex, options = {}) {
|
|
179
|
+
super(
|
|
180
|
+
`Invalid ${nameType} name '${name}': ${validationResult}` +
|
|
181
|
+
(invalidIndex >= 0 ? ` at index ${invalidIndex}` : ''),
|
|
182
|
+
{
|
|
183
|
+
code: 'INVALID_NAME',
|
|
184
|
+
argumentName: nameType,
|
|
185
|
+
providedValue: name,
|
|
186
|
+
details: { validationResult, invalidIndex },
|
|
187
|
+
...options,
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
this.invalidIndex = invalidIndex;
|
|
191
|
+
this.validationResult = validationResult;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Base class for operation/runtime errors
|
|
197
|
+
* @class
|
|
198
|
+
* @extends RclNodeError
|
|
199
|
+
*/
|
|
200
|
+
class OperationError extends RclNodeError {
|
|
201
|
+
/**
|
|
202
|
+
* @param {string} message - Error message
|
|
203
|
+
* @param {object} [options] - Additional options
|
|
204
|
+
*/
|
|
205
|
+
constructor(message, options = {}) {
|
|
206
|
+
super(message, { code: 'OPERATION_ERROR', ...options });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Request timeout error
|
|
212
|
+
* @class
|
|
213
|
+
* @extends OperationError
|
|
214
|
+
*/
|
|
215
|
+
class TimeoutError extends OperationError {
|
|
216
|
+
/**
|
|
217
|
+
* @param {string} operationType - Type of operation that timed out
|
|
218
|
+
* @param {number} timeoutMs - Timeout duration in milliseconds
|
|
219
|
+
* @param {object} [options] - Additional options
|
|
220
|
+
*/
|
|
221
|
+
constructor(operationType, timeoutMs, options = {}) {
|
|
222
|
+
super(`${operationType} timeout after ${timeoutMs}ms`, {
|
|
223
|
+
code: 'TIMEOUT',
|
|
224
|
+
details: { timeoutMs, operationType },
|
|
225
|
+
...options,
|
|
226
|
+
});
|
|
227
|
+
this.timeout = timeoutMs;
|
|
228
|
+
this.operationType = operationType;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Request abortion error
|
|
234
|
+
* @class
|
|
235
|
+
* @extends OperationError
|
|
236
|
+
*/
|
|
237
|
+
class AbortError extends OperationError {
|
|
238
|
+
/**
|
|
239
|
+
* @param {string} operationType - Type of operation that was aborted
|
|
240
|
+
* @param {string} [reason] - Reason for abortion
|
|
241
|
+
* @param {object} [options] - Additional options
|
|
242
|
+
*/
|
|
243
|
+
constructor(operationType, reason, options = {}) {
|
|
244
|
+
super(`${operationType} was aborted` + (reason ? `: ${reason}` : ''), {
|
|
245
|
+
code: 'ABORTED',
|
|
246
|
+
details: { operationType, reason },
|
|
247
|
+
...options,
|
|
248
|
+
});
|
|
249
|
+
this.operationType = operationType;
|
|
250
|
+
this.abortReason = reason;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Service not available error
|
|
256
|
+
* @class
|
|
257
|
+
* @extends OperationError
|
|
258
|
+
*/
|
|
259
|
+
class ServiceNotFoundError extends OperationError {
|
|
260
|
+
/**
|
|
261
|
+
* @param {string} serviceName - Name of the service
|
|
262
|
+
* @param {object} [options] - Additional options
|
|
263
|
+
*/
|
|
264
|
+
constructor(serviceName, options = {}) {
|
|
265
|
+
super(`Service '${serviceName}' is not available`, {
|
|
266
|
+
code: 'SERVICE_NOT_FOUND',
|
|
267
|
+
entityType: 'service',
|
|
268
|
+
entityName: serviceName,
|
|
269
|
+
...options,
|
|
270
|
+
});
|
|
271
|
+
this.serviceName = serviceName;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Remote node not found error
|
|
277
|
+
* @class
|
|
278
|
+
* @extends OperationError
|
|
279
|
+
*/
|
|
280
|
+
class NodeNotFoundError extends OperationError {
|
|
281
|
+
/**
|
|
282
|
+
* @param {string} nodeName - Name of the node
|
|
283
|
+
* @param {object} [options] - Additional options
|
|
284
|
+
*/
|
|
285
|
+
constructor(nodeName, options = {}) {
|
|
286
|
+
super(`Node '${nodeName}' not found or not available`, {
|
|
287
|
+
code: 'NODE_NOT_FOUND',
|
|
288
|
+
entityType: 'node',
|
|
289
|
+
entityName: nodeName,
|
|
290
|
+
...options,
|
|
291
|
+
});
|
|
292
|
+
this.targetNodeName = nodeName;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Base error for parameter operations
|
|
298
|
+
* @class
|
|
299
|
+
* @extends RclNodeError
|
|
300
|
+
*/
|
|
301
|
+
class ParameterError extends RclNodeError {
|
|
302
|
+
/**
|
|
303
|
+
* @param {string} message - Error message
|
|
304
|
+
* @param {string} parameterName - Name of the parameter
|
|
305
|
+
* @param {object} [options] - Additional options
|
|
306
|
+
*/
|
|
307
|
+
constructor(message, parameterName, options = {}) {
|
|
308
|
+
super(message, {
|
|
309
|
+
code: 'PARAMETER_ERROR',
|
|
310
|
+
entityType: 'parameter',
|
|
311
|
+
entityName: parameterName,
|
|
312
|
+
...options,
|
|
313
|
+
});
|
|
314
|
+
this.parameterName = parameterName;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Parameter not found error
|
|
320
|
+
* @class
|
|
321
|
+
* @extends ParameterError
|
|
322
|
+
*/
|
|
323
|
+
class ParameterNotFoundError extends ParameterError {
|
|
324
|
+
/**
|
|
325
|
+
* @param {string} parameterName - Name of the parameter
|
|
326
|
+
* @param {string} nodeName - Name of the node
|
|
327
|
+
* @param {object} [options] - Additional options
|
|
328
|
+
*/
|
|
329
|
+
constructor(parameterName, nodeName, options = {}) {
|
|
330
|
+
super(
|
|
331
|
+
`Parameter '${parameterName}' not found on node '${nodeName}'`,
|
|
332
|
+
parameterName,
|
|
333
|
+
{
|
|
334
|
+
code: 'PARAMETER_NOT_FOUND',
|
|
335
|
+
nodeName,
|
|
336
|
+
...options,
|
|
337
|
+
}
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Parameter type mismatch error
|
|
344
|
+
* @class
|
|
345
|
+
* @extends ParameterError
|
|
346
|
+
*/
|
|
347
|
+
class ParameterTypeError extends ParameterError {
|
|
348
|
+
/**
|
|
349
|
+
* @param {string} parameterName - Name of the parameter
|
|
350
|
+
* @param {string} expectedType - Expected parameter type
|
|
351
|
+
* @param {string} actualType - Actual parameter type
|
|
352
|
+
* @param {object} [options] - Additional options
|
|
353
|
+
*/
|
|
354
|
+
constructor(parameterName, expectedType, actualType, options = {}) {
|
|
355
|
+
super(
|
|
356
|
+
`Type mismatch for parameter '${parameterName}': expected ${expectedType}, got ${actualType}`,
|
|
357
|
+
parameterName,
|
|
358
|
+
{
|
|
359
|
+
code: 'PARAMETER_TYPE_MISMATCH',
|
|
360
|
+
details: { expectedType, actualType },
|
|
361
|
+
...options,
|
|
362
|
+
}
|
|
363
|
+
);
|
|
364
|
+
this.expectedType = expectedType;
|
|
365
|
+
this.actualType = actualType;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Read-only parameter modification error
|
|
371
|
+
* @class
|
|
372
|
+
* @extends ParameterError
|
|
373
|
+
*/
|
|
374
|
+
class ReadOnlyParameterError extends ParameterError {
|
|
375
|
+
/**
|
|
376
|
+
* @param {string} parameterName - Name of the parameter
|
|
377
|
+
* @param {object} [options] - Additional options
|
|
378
|
+
*/
|
|
379
|
+
constructor(parameterName, options = {}) {
|
|
380
|
+
super(
|
|
381
|
+
`Cannot modify read-only parameter '${parameterName}'`,
|
|
382
|
+
parameterName,
|
|
383
|
+
{
|
|
384
|
+
code: 'PARAMETER_READ_ONLY',
|
|
385
|
+
...options,
|
|
386
|
+
}
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Base error for topic operations
|
|
393
|
+
* @class
|
|
394
|
+
* @extends RclNodeError
|
|
395
|
+
*/
|
|
396
|
+
class TopicError extends RclNodeError {
|
|
397
|
+
/**
|
|
398
|
+
* @param {string} message - Error message
|
|
399
|
+
* @param {string} topicName - Name of the topic
|
|
400
|
+
* @param {object} [options] - Additional options
|
|
401
|
+
*/
|
|
402
|
+
constructor(message, topicName, options = {}) {
|
|
403
|
+
super(message, {
|
|
404
|
+
code: 'TOPIC_ERROR',
|
|
405
|
+
entityType: 'topic',
|
|
406
|
+
entityName: topicName,
|
|
407
|
+
...options,
|
|
408
|
+
});
|
|
409
|
+
this.topicName = topicName;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Publisher-specific error
|
|
415
|
+
* @class
|
|
416
|
+
* @extends TopicError
|
|
417
|
+
*/
|
|
418
|
+
class PublisherError extends TopicError {
|
|
419
|
+
/**
|
|
420
|
+
* @param {string} message - Error message
|
|
421
|
+
* @param {string} topicName - Name of the topic
|
|
422
|
+
* @param {object} [options] - Additional options
|
|
423
|
+
*/
|
|
424
|
+
constructor(message, topicName, options = {}) {
|
|
425
|
+
super(message, topicName, {
|
|
426
|
+
code: 'PUBLISHER_ERROR',
|
|
427
|
+
entityType: 'publisher',
|
|
428
|
+
...options,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Subscription-specific error
|
|
435
|
+
* @class
|
|
436
|
+
* @extends TopicError
|
|
437
|
+
*/
|
|
438
|
+
class SubscriptionError extends TopicError {
|
|
439
|
+
/**
|
|
440
|
+
* @param {string} message - Error message
|
|
441
|
+
* @param {string} topicName - Name of the topic
|
|
442
|
+
* @param {object} [options] - Additional options
|
|
443
|
+
*/
|
|
444
|
+
constructor(message, topicName, options = {}) {
|
|
445
|
+
super(message, topicName, {
|
|
446
|
+
code: 'SUBSCRIPTION_ERROR',
|
|
447
|
+
entityType: 'subscription',
|
|
448
|
+
...options,
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Base error for action operations
|
|
455
|
+
* @class
|
|
456
|
+
* @extends RclNodeError
|
|
457
|
+
*/
|
|
458
|
+
class ActionError extends RclNodeError {
|
|
459
|
+
/**
|
|
460
|
+
* @param {string} message - Error message
|
|
461
|
+
* @param {string} actionName - Name of the action
|
|
462
|
+
* @param {object} [options] - Additional options
|
|
463
|
+
*/
|
|
464
|
+
constructor(message, actionName, options = {}) {
|
|
465
|
+
super(message, {
|
|
466
|
+
code: 'ACTION_ERROR',
|
|
467
|
+
entityType: 'action',
|
|
468
|
+
entityName: actionName,
|
|
469
|
+
...options,
|
|
470
|
+
});
|
|
471
|
+
this.actionName = actionName;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Goal rejected by action server
|
|
477
|
+
* @class
|
|
478
|
+
* @extends ActionError
|
|
479
|
+
*/
|
|
480
|
+
class GoalRejectedError extends ActionError {
|
|
481
|
+
/**
|
|
482
|
+
* @param {string} actionName - Name of the action
|
|
483
|
+
* @param {string} goalId - ID of the rejected goal
|
|
484
|
+
* @param {object} [options] - Additional options
|
|
485
|
+
*/
|
|
486
|
+
constructor(actionName, goalId, options = {}) {
|
|
487
|
+
super(`Goal rejected by action server '${actionName}'`, actionName, {
|
|
488
|
+
code: 'GOAL_REJECTED',
|
|
489
|
+
details: { goalId },
|
|
490
|
+
...options,
|
|
491
|
+
});
|
|
492
|
+
this.goalId = goalId;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Action server not found
|
|
498
|
+
* @class
|
|
499
|
+
* @extends ActionError
|
|
500
|
+
*/
|
|
501
|
+
class ActionServerNotFoundError extends ActionError {
|
|
502
|
+
/**
|
|
503
|
+
* @param {string} actionName - Name of the action
|
|
504
|
+
* @param {object} [options] - Additional options
|
|
505
|
+
*/
|
|
506
|
+
constructor(actionName, options = {}) {
|
|
507
|
+
super(`Action server '${actionName}' is not available`, actionName, {
|
|
508
|
+
code: 'ACTION_SERVER_NOT_FOUND',
|
|
509
|
+
...options,
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Wraps errors from native C++ layer with additional context
|
|
516
|
+
* @class
|
|
517
|
+
* @extends RclNodeError
|
|
518
|
+
*/
|
|
519
|
+
class NativeError extends RclNodeError {
|
|
520
|
+
/**
|
|
521
|
+
* @param {string} nativeMessage - Error message from C++ layer
|
|
522
|
+
* @param {string} operation - Operation that failed
|
|
523
|
+
* @param {object} [options] - Additional options
|
|
524
|
+
*/
|
|
525
|
+
constructor(nativeMessage, operation, options = {}) {
|
|
526
|
+
super(`Native operation failed: ${operation} - ${nativeMessage}`, {
|
|
527
|
+
code: 'NATIVE_ERROR',
|
|
528
|
+
details: { nativeMessage, operation },
|
|
529
|
+
...options,
|
|
530
|
+
});
|
|
531
|
+
this.nativeMessage = nativeMessage;
|
|
532
|
+
this.operation = operation;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
module.exports = {
|
|
537
|
+
// Base error
|
|
538
|
+
RclNodeError,
|
|
539
|
+
|
|
540
|
+
// Validation errors
|
|
541
|
+
ValidationError,
|
|
542
|
+
TypeValidationError,
|
|
543
|
+
RangeValidationError,
|
|
544
|
+
NameValidationError,
|
|
545
|
+
|
|
546
|
+
// Operation errors
|
|
547
|
+
OperationError,
|
|
548
|
+
TimeoutError,
|
|
549
|
+
AbortError,
|
|
550
|
+
ServiceNotFoundError,
|
|
551
|
+
NodeNotFoundError,
|
|
552
|
+
|
|
553
|
+
// Parameter errors
|
|
554
|
+
ParameterError,
|
|
555
|
+
ParameterNotFoundError,
|
|
556
|
+
ParameterTypeError,
|
|
557
|
+
ReadOnlyParameterError,
|
|
558
|
+
|
|
559
|
+
// Topic errors
|
|
560
|
+
TopicError,
|
|
561
|
+
PublisherError,
|
|
562
|
+
SubscriptionError,
|
|
563
|
+
|
|
564
|
+
// Action errors
|
|
565
|
+
ActionError,
|
|
566
|
+
GoalRejectedError,
|
|
567
|
+
ActionServerNotFoundError,
|
|
568
|
+
|
|
569
|
+
// Native error
|
|
570
|
+
NativeError,
|
|
571
|
+
};
|
package/lib/event_handler.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
const rclnodejs = require('./native_loader.js');
|
|
18
18
|
const DistroUtils = require('./distro.js');
|
|
19
|
+
const { OperationError } = require('./errors.js');
|
|
19
20
|
const Entity = require('./entity.js');
|
|
20
21
|
|
|
21
22
|
/**
|
|
@@ -79,8 +80,16 @@ class EventHandler extends Entity {
|
|
|
79
80
|
class PublisherEventCallbacks {
|
|
80
81
|
constructor() {
|
|
81
82
|
if (DistroUtils.getDistroId() < DistroUtils.getDistroId('jazzy')) {
|
|
82
|
-
throw new
|
|
83
|
-
'PublisherEventCallbacks is only available in ROS 2 Jazzy and later
|
|
83
|
+
throw new OperationError(
|
|
84
|
+
'PublisherEventCallbacks is only available in ROS 2 Jazzy and later',
|
|
85
|
+
{
|
|
86
|
+
code: 'UNSUPPORTED_ROS_VERSION',
|
|
87
|
+
entityType: 'publisher event callbacks',
|
|
88
|
+
details: {
|
|
89
|
+
requiredVersion: 'jazzy',
|
|
90
|
+
currentVersion: DistroUtils.getDistroId(),
|
|
91
|
+
},
|
|
92
|
+
}
|
|
84
93
|
);
|
|
85
94
|
}
|
|
86
95
|
this._deadline = null;
|
|
@@ -262,8 +271,16 @@ class PublisherEventCallbacks {
|
|
|
262
271
|
class SubscriptionEventCallbacks {
|
|
263
272
|
constructor() {
|
|
264
273
|
if (DistroUtils.getDistroId() < DistroUtils.getDistroId('jazzy')) {
|
|
265
|
-
throw new
|
|
266
|
-
'SubscriptionEventCallbacks is only available in ROS 2 Jazzy and later
|
|
274
|
+
throw new OperationError(
|
|
275
|
+
'SubscriptionEventCallbacks is only available in ROS 2 Jazzy and later',
|
|
276
|
+
{
|
|
277
|
+
code: 'UNSUPPORTED_ROS_VERSION',
|
|
278
|
+
entityType: 'subscription event callbacks',
|
|
279
|
+
details: {
|
|
280
|
+
requiredVersion: 'jazzy',
|
|
281
|
+
currentVersion: DistroUtils.getDistroId(),
|
|
282
|
+
},
|
|
283
|
+
}
|
|
267
284
|
);
|
|
268
285
|
}
|
|
269
286
|
this._deadline = null;
|