rclnodejs 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +4 -4
  2. package/binding.gyp +5 -0
  3. package/index.js +26 -3
  4. package/lib/context.js +4 -2
  5. package/lib/event_handler.js +474 -0
  6. package/lib/lifecycle.js +9 -0
  7. package/lib/lifecycle_publisher.js +2 -2
  8. package/lib/node.js +163 -28
  9. package/lib/publisher.js +31 -4
  10. package/lib/serialization.js +60 -0
  11. package/lib/subscription.js +48 -4
  12. package/lib/type_description_service.js +27 -1
  13. package/package.json +1 -1
  14. package/rosidl_gen/templates/message.dot +1 -1
  15. package/scripts/npmjs-readme.md +4 -4
  16. package/src/addon.cpp +4 -0
  17. package/src/executor.cpp +3 -4
  18. package/src/handle_manager.cpp +13 -2
  19. package/src/handle_manager.h +4 -1
  20. package/src/macros.h +17 -1
  21. package/src/rcl_action_client_bindings.cpp +3 -2
  22. package/src/rcl_action_goal_bindings.cpp +3 -2
  23. package/src/rcl_action_server_bindings.cpp +7 -5
  24. package/src/rcl_client_bindings.cpp +4 -3
  25. package/src/rcl_context_bindings.cpp +29 -19
  26. package/src/rcl_event_handle_bindings.cpp +294 -0
  27. package/src/rcl_event_handle_bindings.h +26 -0
  28. package/src/rcl_guard_condition_bindings.cpp +3 -2
  29. package/src/rcl_lifecycle_bindings.cpp +18 -4
  30. package/src/rcl_node_bindings.cpp +111 -3
  31. package/src/rcl_publisher_bindings.cpp +4 -3
  32. package/src/rcl_serialization_bindings.cpp +116 -0
  33. package/src/rcl_serialization_bindings.h +26 -0
  34. package/src/rcl_service_bindings.cpp +4 -3
  35. package/src/rcl_subscription_bindings.cpp +3 -2
  36. package/src/rcl_time_point_bindings.cpp +3 -2
  37. package/src/rcl_timer_bindings.cpp +8 -6
  38. package/src/rcl_utilities.cpp +31 -0
  39. package/src/rcl_utilities.h +7 -0
  40. package/tsconfig.json +2 -2
  41. package/types/context.d.ts +3 -2
  42. package/types/index.d.ts +26 -1
  43. package/types/lifecycle.d.ts +7 -0
  44. package/types/node.d.ts +60 -10
package/lib/node.js CHANGED
@@ -41,6 +41,9 @@ const TimeSource = require('./time_source.js');
41
41
  const Timer = require('./timer.js');
42
42
  const TypeDescriptionService = require('./type_description_service.js');
43
43
  const Entity = require('./entity.js');
44
+ const { SubscriptionEventCallbacks } = require('../lib/event_handler.js');
45
+ const { PublisherEventCallbacks } = require('../lib/event_handler.js');
46
+ const { validateFullTopicName } = require('./validator.js');
44
47
 
45
48
  // Parameter event publisher constants
46
49
  const PARAMETER_EVENT_MSG_TYPE = 'rcl_interfaces/msg/ParameterEvent';
@@ -64,7 +67,9 @@ class Node extends rclnodejs.ShadowNode {
64
67
  nodeName,
65
68
  namespace = '',
66
69
  context = Context.defaultContext(),
67
- options = NodeOptions.defaultOptions
70
+ options = NodeOptions.defaultOptions,
71
+ args = [],
72
+ useGlobalArguments = true
68
73
  ) {
69
74
  super();
70
75
 
@@ -72,7 +77,7 @@ class Node extends rclnodejs.ShadowNode {
72
77
  throw new TypeError('Invalid argument.');
73
78
  }
74
79
 
75
- this._init(nodeName, namespace, options, context);
80
+ this._init(nodeName, namespace, options, context, args, useGlobalArguments);
76
81
  debug(
77
82
  'Finish initializing node, name = %s and namespace = %s.',
78
83
  nodeName,
@@ -80,8 +85,14 @@ class Node extends rclnodejs.ShadowNode {
80
85
  );
81
86
  }
82
87
 
83
- _init(name, namespace, options, context) {
84
- this.handle = rclnodejs.createNode(name, namespace, context.handle);
88
+ _init(name, namespace, options, context, args, useGlobalArguments) {
89
+ this.handle = rclnodejs.createNode(
90
+ name,
91
+ namespace,
92
+ context.handle,
93
+ args,
94
+ useGlobalArguments
95
+ );
85
96
  Object.defineProperty(this, 'handle', {
86
97
  configurable: false,
87
98
  writable: false,
@@ -96,6 +107,7 @@ class Node extends rclnodejs.ShadowNode {
96
107
  this._services = [];
97
108
  this._timers = [];
98
109
  this._guards = [];
110
+ this._events = [];
99
111
  this._actionClients = [];
100
112
  this._actionServers = [];
101
113
  this._rateTimerServer = null;
@@ -181,6 +193,9 @@ class Node extends rclnodejs.ShadowNode {
181
193
  let actionServersReady = this._actionServers.filter((actionServer) =>
182
194
  handles.includes(actionServer.handle)
183
195
  );
196
+ let eventsReady = this._events.filter((event) =>
197
+ handles.includes(event.handle)
198
+ );
184
199
 
185
200
  timersReady.forEach((timer) => {
186
201
  if (timer.isReady()) {
@@ -189,6 +204,10 @@ class Node extends rclnodejs.ShadowNode {
189
204
  }
190
205
  });
191
206
 
207
+ eventsReady.forEach((event) => {
208
+ event.takeData();
209
+ });
210
+
192
211
  for (const subscription of subscriptionsReady) {
193
212
  if (subscription.isDestroyed()) continue;
194
213
  if (subscription.isRaw) {
@@ -588,27 +607,39 @@ class Node extends rclnodejs.ShadowNode {
588
607
  * @param {object} options - The options argument used to parameterize the publisher.
589
608
  * @param {boolean} options.enableTypedArray - The topic will use TypedArray if necessary, default: true.
590
609
  * @param {QoS} options.qos - ROS Middleware "quality of service" settings for the publisher, default: QoS.profileDefault.
610
+ * @param {PublisherEventCallbacks} eventCallbacks - The event callbacks for the publisher.
591
611
  * @return {Publisher} - An instance of Publisher.
592
612
  */
593
- createPublisher(typeClass, topic, options) {
594
- return this._createPublisher(typeClass, topic, options, Publisher);
613
+ createPublisher(typeClass, topic, options, eventCallbacks) {
614
+ return this._createPublisher(
615
+ typeClass,
616
+ topic,
617
+ options,
618
+ Publisher,
619
+ eventCallbacks
620
+ );
595
621
  }
596
622
 
597
- _createPublisher(typeClass, topic, options, publisherClass) {
623
+ _createPublisher(typeClass, topic, options, publisherClass, eventCallbacks) {
598
624
  if (typeof typeClass === 'string' || typeof typeClass === 'object') {
599
625
  typeClass = loader.loadInterface(typeClass);
600
626
  }
601
627
  options = this._validateOptions(options);
602
628
 
603
- if (typeof typeClass !== 'function' || typeof topic !== 'string') {
629
+ if (
630
+ typeof typeClass !== 'function' ||
631
+ typeof topic !== 'string' ||
632
+ (eventCallbacks && !(eventCallbacks instanceof PublisherEventCallbacks))
633
+ ) {
604
634
  throw new TypeError('Invalid argument');
605
635
  }
606
636
 
607
637
  let publisher = publisherClass.createPublisher(
608
- this.handle,
638
+ this,
609
639
  typeClass,
610
640
  topic,
611
- options
641
+ options,
642
+ eventCallbacks
612
643
  );
613
644
  debug('Finish creating publisher, topic = %s.', topic);
614
645
  this._publishers.push(publisher);
@@ -643,12 +674,13 @@ class Node extends rclnodejs.ShadowNode {
643
674
  * the ‘parameters’ (i.e., "%n" tokens) in the filter_expression. The number of supplied parameters must
644
675
  * fit with the requested values in the filter_expression (i.e., the number of %n tokens). default: undefined.
645
676
  * @param {SubscriptionCallback} callback - The callback to be call when receiving the topic subscribed. The topic will be an instance of null-terminated Buffer when options.isRaw is true.
677
+ * @param {SubscriptionEventCallbacks} eventCallbacks - The event callbacks for the subscription.
646
678
  * @return {Subscription} - An instance of Subscription.
647
679
  * @throws {ERROR} - May throw an RMW error if content-filter is malformed.
648
680
  * @see {@link SubscriptionCallback}
649
681
  * @see {@link https://www.omg.org/spec/DDS/1.4/PDF|Content-filter details at DDS 1.4 specification, Annex B}
650
682
  */
651
- createSubscription(typeClass, topic, options, callback) {
683
+ createSubscription(typeClass, topic, options, callback, eventCallbacks) {
652
684
  if (typeof typeClass === 'string' || typeof typeClass === 'object') {
653
685
  typeClass = loader.loadInterface(typeClass);
654
686
  }
@@ -662,17 +694,20 @@ class Node extends rclnodejs.ShadowNode {
662
694
  if (
663
695
  typeof typeClass !== 'function' ||
664
696
  typeof topic !== 'string' ||
665
- typeof callback !== 'function'
697
+ typeof callback !== 'function' ||
698
+ (eventCallbacks &&
699
+ !(eventCallbacks instanceof SubscriptionEventCallbacks))
666
700
  ) {
667
701
  throw new TypeError('Invalid argument');
668
702
  }
669
703
 
670
704
  let subscription = Subscription.createSubscription(
671
- this.handle,
705
+ this,
672
706
  typeClass,
673
707
  topic,
674
708
  options,
675
- callback
709
+ callback,
710
+ eventCallbacks
676
711
  );
677
712
  debug('Finish creating subscription, topic = %s.', topic);
678
713
  this._subscriptions.push(subscription);
@@ -836,6 +871,12 @@ class Node extends rclnodejs.ShadowNode {
836
871
  if (!(publisher instanceof Publisher)) {
837
872
  throw new TypeError('Invalid argument');
838
873
  }
874
+ if (publisher.events) {
875
+ publisher.events.forEach((event) => {
876
+ this._destroyEntity(event, this._events);
877
+ });
878
+ publisher.events = [];
879
+ }
839
880
  this._destroyEntity(publisher, this._publishers, false);
840
881
  }
841
882
 
@@ -848,6 +889,13 @@ class Node extends rclnodejs.ShadowNode {
848
889
  if (!(subscription instanceof Subscription)) {
849
890
  throw new TypeError('Invalid argument');
850
891
  }
892
+ if (subscription.events) {
893
+ subscription.events.forEach((event) => {
894
+ this._destroyEntity(event, this._events);
895
+ });
896
+ subscription.events = [];
897
+ }
898
+
851
899
  this._destroyEntity(subscription, this._subscriptions);
852
900
  }
853
901
 
@@ -1025,27 +1073,57 @@ class Node extends rclnodejs.ShadowNode {
1025
1073
  }
1026
1074
 
1027
1075
  /**
1028
- * Get a list of publishers on a given topic.
1029
- * @param {string} topic - the topic name to get the publishers for.
1030
- * @param {boolean} noDemangle - if `true`, `topic_name` needs to be a valid middleware topic name,
1031
- * otherwise it should be a valid ROS topic name.
1076
+ * Return a list of publishers on a given topic.
1077
+ *
1078
+ * The returned parameter is a list of TopicEndpointInfo objects, where each will contain
1079
+ * the node name, node namespace, topic type, topic endpoint's GID, and its QoS profile.
1080
+ *
1081
+ * When the `no_mangle` parameter is `true`, the provided `topic` should be a valid
1082
+ * topic name for the middleware (useful when combining ROS with native middleware (e.g. DDS)
1083
+ * apps). When the `no_mangle` parameter is `false`, the provided `topic` should
1084
+ * follow ROS topic name conventions.
1085
+ *
1086
+ * `topic` may be a relative, private, or fully qualified topic name.
1087
+ * A relative or private topic will be expanded using this node's namespace and name.
1088
+ * The queried `topic` is not remapped.
1089
+ *
1090
+ * @param {string} topic - The topic on which to find the publishers.
1091
+ * @param {boolean} [noDemangle=false] - If `true`, `topic` needs to be a valid middleware topic
1092
+ * name, otherwise it should be a valid ROS topic name. Defaults to `false`.
1032
1093
  * @returns {Array} - list of publishers
1033
1094
  */
1034
- getPublishersInfoByTopic(topic, noDemangle) {
1035
- return rclnodejs.getPublishersInfoByTopic(this.handle, topic, noDemangle);
1095
+ getPublishersInfoByTopic(topic, noDemangle = false) {
1096
+ return rclnodejs.getPublishersInfoByTopic(
1097
+ this.handle,
1098
+ this._getValidatedTopic(topic, noDemangle),
1099
+ noDemangle
1100
+ );
1036
1101
  }
1037
1102
 
1038
1103
  /**
1039
- * Get a list of subscriptions on a given topic.
1040
- * @param {string} topic - the topic name to get the subscriptions for.
1041
- * @param {boolean} noDemangle - if `true`, `topic_name` needs to be a valid middleware topic name,
1042
- * otherwise it should be a valid ROS topic name.
1104
+ * Return a list of subscriptions on a given topic.
1105
+ *
1106
+ * The returned parameter is a list of TopicEndpointInfo objects, where each will contain
1107
+ * the node name, node namespace, topic type, topic endpoint's GID, and its QoS profile.
1108
+ *
1109
+ * When the `no_mangle` parameter is `true`, the provided `topic` should be a valid
1110
+ * topic name for the middleware (useful when combining ROS with native middleware (e.g. DDS)
1111
+ * apps). When the `no_mangle` parameter is `false`, the provided `topic` should
1112
+ * follow ROS topic name conventions.
1113
+ *
1114
+ * `topic` may be a relative, private, or fully qualified topic name.
1115
+ * A relative or private topic will be expanded using this node's namespace and name.
1116
+ * The queried `topic` is not remapped.
1117
+ *
1118
+ * @param {string} topic - The topic on which to find the subscriptions.
1119
+ * @param {boolean} [noDemangle=false] - If `true`, `topic` needs to be a valid middleware topic
1120
+ name, otherwise it should be a valid ROS topic name. Defaults to `false`.
1043
1121
  * @returns {Array} - list of subscriptions
1044
1122
  */
1045
- getSubscriptionsInfoByTopic(topic, noDemangle) {
1123
+ getSubscriptionsInfoByTopic(topic, noDemangle = false) {
1046
1124
  return rclnodejs.getSubscriptionsInfoByTopic(
1047
1125
  this.handle,
1048
- topic,
1126
+ this._getValidatedTopic(topic, noDemangle),
1049
1127
  noDemangle
1050
1128
  );
1051
1129
  }
@@ -1381,7 +1459,7 @@ class Node extends rclnodejs.ShadowNode {
1381
1459
  * Determine if a parameter descriptor exists.
1382
1460
  *
1383
1461
  * @param {string} name - The name of a descriptor to for.
1384
- * @return {boolean} - True if a descriptor has been declared; otherwise false.
1462
+ * @return {boolean} - true if a descriptor has been declared; otherwise false.
1385
1463
  */
1386
1464
  hasParameterDescriptor(name) {
1387
1465
  return !!this.getParameterDescriptor(name);
@@ -1637,6 +1715,50 @@ class Node extends rclnodejs.ShadowNode {
1637
1715
  return rclnodejs.getFullyQualifiedName(this.handle);
1638
1716
  }
1639
1717
 
1718
+ /**
1719
+ * Get the RMW implementation identifier
1720
+ * @returns {string} - The RMW implementation identifier.
1721
+ */
1722
+ getRMWImplementationIdentifier() {
1723
+ return rclnodejs.getRMWImplementationIdentifier();
1724
+ }
1725
+
1726
+ /**
1727
+ * Return a topic name expanded and remapped.
1728
+ * @param {string} topicName - Topic name to be expanded and remapped.
1729
+ * @param {boolean} [onlyExpand=false] - If `true`, remapping rules won't be applied.
1730
+ * @returns {string} - A fully qualified topic name.
1731
+ */
1732
+ resolveTopicName(topicName, onlyExpand = false) {
1733
+ if (typeof topicName !== 'string') {
1734
+ throw new TypeError('Invalid argument: expected string');
1735
+ }
1736
+ return rclnodejs.resolveName(
1737
+ this.handle,
1738
+ topicName,
1739
+ onlyExpand,
1740
+ /*isService=*/ false
1741
+ );
1742
+ }
1743
+
1744
+ /**
1745
+ * Return a service name expanded and remapped.
1746
+ * @param {string} service - Service name to be expanded and remapped.
1747
+ * @param {boolean} [onlyExpand=false] - If `true`, remapping rules won't be applied.
1748
+ * @returns {string} - A fully qualified service name.
1749
+ */
1750
+ resolveServiceName(service, onlyExpand = false) {
1751
+ if (typeof service !== 'string') {
1752
+ throw new TypeError('Invalid argument: expected string');
1753
+ }
1754
+ return rclnodejs.resolveName(
1755
+ this.handle,
1756
+ service,
1757
+ onlyExpand,
1758
+ /*isService=*/ true
1759
+ );
1760
+ }
1761
+
1640
1762
  // returns on 1st error or result {successful, reason}
1641
1763
  _validateParameters(parameters = [], declareParameterMode = false) {
1642
1764
  for (const parameter of parameters) {
@@ -1761,7 +1883,7 @@ class Node extends rclnodejs.ShadowNode {
1761
1883
  return result;
1762
1884
  });
1763
1885
 
1764
- Type.destoryRawROS(message);
1886
+ Type.destroyRawROS(message);
1765
1887
  }
1766
1888
 
1767
1889
  _addActionClient(actionClient) {
@@ -1773,6 +1895,19 @@ class Node extends rclnodejs.ShadowNode {
1773
1895
  this._actionServers.push(actionServer);
1774
1896
  this.syncHandles();
1775
1897
  }
1898
+
1899
+ _getValidatedTopic(topicName, noDemangle) {
1900
+ if (noDemangle) {
1901
+ return topicName;
1902
+ }
1903
+ const fqTopicName = rclnodejs.expandTopicName(
1904
+ topicName,
1905
+ this.name(),
1906
+ this.namespace()
1907
+ );
1908
+ validateFullTopicName(fqTopicName);
1909
+ return rclnodejs.remapTopicName(this.handle, fqTopicName);
1910
+ }
1776
1911
  }
1777
1912
 
1778
1913
  /**
package/lib/publisher.js CHANGED
@@ -24,8 +24,12 @@ const Entity = require('./entity.js');
24
24
  */
25
25
 
26
26
  class Publisher extends Entity {
27
- constructor(handle, typeClass, topic, options) {
27
+ constructor(handle, typeClass, topic, options, node, eventCallbacks) {
28
28
  super(handle, typeClass, options);
29
+ if (node && eventCallbacks) {
30
+ this._events = eventCallbacks.createEventHandlers(this.handle);
31
+ node._events.push(...this._events);
32
+ }
29
33
  }
30
34
 
31
35
  /**
@@ -60,17 +64,24 @@ class Publisher extends Entity {
60
64
  debug(`Message of topic ${this.topic} has been published.`);
61
65
  }
62
66
 
63
- static createPublisher(nodeHandle, typeClass, topic, options) {
67
+ static createPublisher(node, typeClass, topic, options, eventCallbacks) {
64
68
  let type = typeClass.type();
65
69
  let handle = rclnodejs.createPublisher(
66
- nodeHandle,
70
+ node.handle,
67
71
  type.pkgName,
68
72
  type.subFolder,
69
73
  type.interfaceName,
70
74
  topic,
71
75
  options.qos
72
76
  );
73
- return new Publisher(handle, typeClass, topic, options);
77
+ return new Publisher(
78
+ handle,
79
+ typeClass,
80
+ topic,
81
+ options,
82
+ node,
83
+ eventCallbacks
84
+ );
74
85
  }
75
86
 
76
87
  /**
@@ -99,6 +110,22 @@ class Publisher extends Entity {
99
110
  waitForAllAcked(timeout) {
100
111
  return rclnodejs.waitForAllAcked(this._handle, timeout);
101
112
  }
113
+
114
+ /**
115
+ * Get the event handlers for this publisher.
116
+ * @returns {Array} The array of event handlers for this publisher.
117
+ */
118
+ get events() {
119
+ return this._events;
120
+ }
121
+
122
+ /**
123
+ * Set the event handlers for this publisher.
124
+ * @param {Array} events - The array of event handlers to be set for this publisher.
125
+ */
126
+ set events(events) {
127
+ this._events = events;
128
+ }
102
129
  }
103
130
 
104
131
  module.exports = Publisher;
@@ -0,0 +1,60 @@
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
+ 'use strict';
16
+
17
+ const rclnodejs = require('bindings')('rclnodejs');
18
+
19
+ class Serialization {
20
+ /**
21
+ * Serialize a message to a buffer.
22
+ * @param {object} message - The message to serialize.
23
+ * @param {function} typeClass - The class of the message type to serialize.
24
+ * @return {Buffer} The serialized message as a Buffer.
25
+ */
26
+ static serializeMessage(message, typeClass) {
27
+ if (!(message instanceof typeClass)) {
28
+ throw new TypeError('Message must be a valid ros2 message type');
29
+ }
30
+ return rclnodejs.serialize(
31
+ typeClass.type().pkgName,
32
+ typeClass.type().subFolder,
33
+ typeClass.type().interfaceName,
34
+ message.serialize()
35
+ );
36
+ }
37
+
38
+ /**
39
+ * Deserialize a message from a buffer.
40
+ * @param {Buffer} buffer - The buffer containing the serialized message.
41
+ * @param {function} typeClass - The class of the message type to deserialize into.
42
+ * @return {object} The deserialized message object.
43
+ */
44
+ static deserializeMessage(buffer, typeClass) {
45
+ if (!(buffer instanceof Buffer)) {
46
+ throw new TypeError('Buffer is required for deserialization');
47
+ }
48
+ const rosMsg = new typeClass();
49
+ rclnodejs.deserialize(
50
+ typeClass.type().pkgName,
51
+ typeClass.type().subFolder,
52
+ typeClass.type().interfaceName,
53
+ buffer,
54
+ rosMsg.toRawROS()
55
+ );
56
+ return rosMsg;
57
+ }
58
+ }
59
+
60
+ module.exports = Serialization;
@@ -29,11 +29,24 @@ const debug = require('debug')('rclnodejs:subscription');
29
29
  */
30
30
 
31
31
  class Subscription extends Entity {
32
- constructor(handle, typeClass, topic, options, callback) {
32
+ constructor(
33
+ handle,
34
+ typeClass,
35
+ topic,
36
+ options,
37
+ callback,
38
+ node,
39
+ eventCallbacks
40
+ ) {
33
41
  super(handle, typeClass, options);
34
42
  this._topic = topic;
35
43
  this._callback = callback;
36
44
  this._isRaw = options.isRaw || false;
45
+
46
+ if (node && eventCallbacks) {
47
+ this._events = eventCallbacks.createEventHandlers(this.handle);
48
+ node._events.push(...this._events);
49
+ }
37
50
  }
38
51
 
39
52
  processResponse(msg) {
@@ -45,7 +58,14 @@ class Subscription extends Entity {
45
58
  }
46
59
  }
47
60
 
48
- static createSubscription(nodeHandle, typeClass, topic, options, callback) {
61
+ static createSubscription(
62
+ node,
63
+ typeClass,
64
+ topic,
65
+ options,
66
+ callback,
67
+ eventCallbacks
68
+ ) {
49
69
  let type = typeClass.type();
50
70
 
51
71
  // convert contentFilter.parameters to a string[]
@@ -56,14 +76,22 @@ class Subscription extends Entity {
56
76
  }
57
77
 
58
78
  let handle = rclnodejs.createSubscription(
59
- nodeHandle,
79
+ node.handle,
60
80
  type.pkgName,
61
81
  type.subFolder,
62
82
  type.interfaceName,
63
83
  topic,
64
84
  options
65
85
  );
66
- return new Subscription(handle, typeClass, topic, options, callback);
86
+ return new Subscription(
87
+ handle,
88
+ typeClass,
89
+ topic,
90
+ options,
91
+ callback,
92
+ node,
93
+ eventCallbacks
94
+ );
67
95
  }
68
96
 
69
97
  /**
@@ -124,6 +152,22 @@ class Subscription extends Entity {
124
152
  get publisherCount() {
125
153
  return rclnodejs.getPublisherCount(this._handle);
126
154
  }
155
+
156
+ /**
157
+ * Get the event handlers for this subscription.
158
+ * @returns {Array} The array of event handlers for this subscription.
159
+ */
160
+ get events() {
161
+ return this._events;
162
+ }
163
+
164
+ /**
165
+ * Set the event handlers for this subscription.
166
+ * @param {Array} events - The array of event handlers for this subscription.
167
+ */
168
+ set events(events) {
169
+ this._events = events;
170
+ }
127
171
  }
128
172
 
129
173
  module.exports = Subscription;
@@ -18,6 +18,12 @@ const loader = require('./interface_loader.js');
18
18
  const rclnodejs = require('bindings')('rclnodejs');
19
19
  const Service = require('./service.js');
20
20
 
21
+ const {
22
+ ParameterType,
23
+ Parameter,
24
+ ParameterDescriptor,
25
+ } = require('../lib/parameter.js');
26
+
21
27
  // This class is used to create a TypeDescriptionService which can be used to
22
28
  // retrieve information about types used by the node’s publishers, subscribers,
23
29
  // services or actions.
@@ -32,10 +38,30 @@ class TypeDescriptionService {
32
38
  'type_description_interfaces/srv/GetTypeDescription'
33
39
  );
34
40
  this._typeDescriptionService = null;
41
+
42
+ this._enabled = false;
43
+ const startTypeDescriptionServiceParam = 'start_type_description_service';
44
+ if (!node.hasParameter(startTypeDescriptionServiceParam)) {
45
+ node.declareParameter(
46
+ new Parameter(
47
+ startTypeDescriptionServiceParam,
48
+ ParameterType.PARAMETER_BOOL,
49
+ true
50
+ ),
51
+ new ParameterDescriptor(
52
+ startTypeDescriptionServiceParam,
53
+ ParameterType.PARAMETER_BOOL,
54
+ 'If enabled, start the ~/get_type_description service.',
55
+ true
56
+ )
57
+ );
58
+ }
59
+ const param = node.getParameter(startTypeDescriptionServiceParam);
60
+ this._enabled = param.value;
35
61
  }
36
62
 
37
63
  start() {
38
- if (this._typeDescriptionService) {
64
+ if (!this._enabled || this._typeDescriptionService) {
39
65
  return;
40
66
  }
41
67
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rclnodejs",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "ROS2.0 JavaScript client with Node.js",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
@@ -506,7 +506,7 @@ class {{=objectWrapper}} {
506
506
  {{~}}
507
507
  }
508
508
 
509
- static destoryRawROS(msg) {
509
+ static destroyRawROS(msg) {
510
510
  {{=objectWrapper}}.freeStruct(msg.refObject);
511
511
  }
512
512
 
@@ -1,4 +1,4 @@
1
- # rclnodejs ![GitHub Workflow Status](https://github.com/RobotWebTools/rclnodejs/actions/workflows/linux-build-and-test.yml/badge.svg?branch=jazzy)
1
+ # rclnodejs [![Linux](https://github.com/RobotWebTools/rclnodejs/actions/workflows/linux-x64-build-and-test.yml/badge.svg?branch=develop)](https://github.com/RobotWebTools/rclnodejs/actions/workflows/linux-x64-build-and-test.yml?query=branch%3Adevelop)[![Linux](https://github.com/RobotWebTools/rclnodejs/actions/workflows/linux-arm64-build-and-test.yml/badge.svg?branch=develop)](https://github.com/RobotWebTools/rclnodejs/actions/workflows/linux-arm64-build-and-test.yml?query=branch%3Adevelop)
2
2
 
3
3
  `rclnodejs` is a Node.js client for the Robot Operating System (ROS 2). It provides a simple and easy JavaScript API for ROS 2 programming. TypeScript declarations are included to support use of rclnodejs in TypeScript projects.
4
4
 
@@ -22,8 +22,8 @@ rclnodejs.init().then(() => {
22
22
 
23
23
  **ROS 2 SDK**
24
24
 
25
- - See the ROS 2 SDK [Installation Guide](https://docs.ros.org/en/jazzy/Installation.html) for details.
26
- - **DON'T FORGET TO [SOURCE THE ROS 2 STARTUP FILES](https://docs.ros.org/en/jazzy/Tutorials/Beginner-CLI-Tools/Configuring-ROS2-Environment.html#source-the-setup-files)**
25
+ - See the ROS 2 SDK [Installation Guide](https://docs.ros.org/en/kilted/Installation.html) for details.
26
+ - **DON'T FORGET TO [SOURCE THE ROS 2 STARTUP FILES](https://docs.ros.org/en/kilted/Tutorials/Beginner-CLI-Tools/Configuring-ROS2-Environment.htmls)**
27
27
 
28
28
  ## Install rclnodejs
29
29
 
@@ -45,7 +45,7 @@ npm i rclnodejs@x.y.z
45
45
 
46
46
  | RCLNODEJS Version | Compatible ROS 2 LTS |
47
47
  | :----------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
48
- | latest version (currently [v1.1.0](https://github.com/RobotWebTools/rclnodejs/tree/1.1.0)) | [Kilted](https://github.com/RobotWebTools/rclnodejs/tree/kilted)<br>[Jazzy](https://github.com/RobotWebTools/rclnodejs/tree/jazzy)<br>[Humble](https://github.com/RobotWebTools/rclnodejs/tree/humble-hawksbill) |
48
+ | latest version (currently [v1.3.0](https://github.com/RobotWebTools/rclnodejs/tree/1.3.0)) | [Kilted](https://github.com/RobotWebTools/rclnodejs/tree/kilted)<br>[Jazzy](https://github.com/RobotWebTools/rclnodejs/tree/jazzy)<br>[Humble](https://github.com/RobotWebTools/rclnodejs/tree/humble-hawksbill) |
49
49
 
50
50
  ## Documentation
51
51
 
package/src/addon.cpp CHANGED
@@ -30,11 +30,13 @@
30
30
  #include "rcl_names_bindings.h"
31
31
  #include "rcl_node_bindings.h"
32
32
  #include "rcl_publisher_bindings.h"
33
+ #include "rcl_serialization_bindings.h"
33
34
  #include "rcl_service_bindings.h"
34
35
  #include "rcl_subscription_bindings.h"
35
36
  #include "rcl_time_point_bindings.h"
36
37
  #include "rcl_timer_bindings.h"
37
38
  #if ROS_VERSION > 2205 // ROS2 > Humble
39
+ #include "rcl_event_handle_bindings.h"
38
40
  #include "rcl_type_description_service_bindings.h"
39
41
  #endif
40
42
  #include "rcl_utilities.h"
@@ -84,8 +86,10 @@ Napi::Object InitModule(Napi::Env env, Napi::Object exports) {
84
86
  rclnodejs::InitTimerBindings(env, exports);
85
87
  #if ROS_VERSION > 2205 // ROS2 > Humble
86
88
  rclnodejs::InitTypeDescriptionServiceBindings(env, exports);
89
+ rclnodejs::InitEventHandleBindings(env, exports);
87
90
  #endif
88
91
  rclnodejs::InitLifecycleBindings(env, exports);
92
+ rclnodejs::InitSerializationBindings(env, exports);
89
93
  rclnodejs::ShadowNode::Init(env, exports);
90
94
  rclnodejs::RclHandle::Init(env, exports);
91
95