Skip to main content

ros2_client/
node.rs

1use std::{
2  collections::{BTreeMap, BTreeSet},
3  error::Error,
4  fmt,
5  pin::Pin,
6  sync::{
7    atomic::{AtomicBool, Ordering},
8    Arc, Mutex,
9  },
10};
11
12use futures::{
13  pin_mut, stream, stream::FusedStream, task, task::Poll, Future, FutureExt, Stream, StreamExt,
14};
15use async_channel::Receiver;
16#[allow(unused_imports)]
17use log::{debug, error, info, trace, warn};
18use serde::Serialize;
19use rustdds::{
20  dds::{CreateError, CreateResult},
21  *,
22};
23
24use crate::{
25  action::*,
26  builtin_interfaces,
27  context::{Context, DEFAULT_SUBSCRIPTION_QOS},
28  entities_info::{NodeEntitiesInfo, ParticipantEntitiesInfo},
29  gid::Gid,
30  log::Log,
31  names::*,
32  parameters::*,
33  pubsub::{Publisher, Subscription},
34  rcl_interfaces,
35  ros_time::ROSTime,
36  rosout::{NodeLoggingHandle, RosoutRaw},
37  service::{Client, Server, Service, ServiceMapping},
38};
39
40type ParameterFunc = dyn Fn(&str, &ParameterValue) -> SetParametersResult + Send + Sync;
41/// Configuration of [Node]
42/// This is a builder-like struct.
43///
44/// The NodeOptions struct does not contain
45/// node_name, context, or namespace, because
46/// they ae always needed and have no reasonable default.
47#[must_use]
48pub struct NodeOptions {
49  #[allow(dead_code)]
50  cli_args: Vec<String>,
51  #[allow(dead_code)]
52  use_global_arguments: bool, // process-wide command line args
53  enable_rosout: bool, // use rosout topic for logging?
54  enable_rosout_reading: bool,
55  start_parameter_services: bool,
56  declared_parameters: Vec<Parameter>,
57  allow_undeclared_parameters: bool,
58  parameter_validator: Option<Box<ParameterFunc>>,
59  parameter_set_action: Option<Box<ParameterFunc>>,
60}
61
62impl NodeOptions {
63  /// Get a default NodeOptions
64  pub fn new() -> NodeOptions {
65    // These defaults are from rclpy reference
66    // https://docs.ros2.org/latest/api/rclpy/api/node.html
67    NodeOptions {
68      cli_args: Vec::new(),
69      use_global_arguments: true,
70      enable_rosout: true,
71      enable_rosout_reading: false,
72      start_parameter_services: true,
73      declared_parameters: Vec::new(),
74      allow_undeclared_parameters: false,
75      parameter_validator: None,
76      parameter_set_action: None,
77    }
78  }
79  pub fn enable_rosout(self, enable_rosout: bool) -> NodeOptions {
80    NodeOptions {
81      enable_rosout,
82      ..self
83    }
84  }
85
86  pub fn read_rosout(self, enable_rosout_reading: bool) -> NodeOptions {
87    NodeOptions {
88      enable_rosout_reading,
89      ..self
90    }
91  }
92
93  pub fn declare_parameter(mut self, name: &str, value: ParameterValue) -> NodeOptions {
94    self.declared_parameters.push(Parameter {
95      name: name.to_owned(),
96      value,
97    });
98    // TODO: check for duplicate parameter names
99    self
100  }
101
102  pub fn parameter_validator(mut self, validator: Box<ParameterFunc>) -> NodeOptions {
103    self.parameter_validator = Some(validator);
104    self
105  }
106
107  pub fn parameter_set_action(mut self, action: Box<ParameterFunc>) -> NodeOptions {
108    self.parameter_set_action = Some(action);
109    self
110  }
111}
112
113impl Default for NodeOptions {
114  fn default() -> Self {
115    Self::new()
116  }
117}
118// ----------------------------------------------------------------------------------------------------
119// ----------------------------------------------------------------------------------------------------
120
121/// DDS or ROS 2 Discovery events.
122#[allow(clippy::large_enum_variant)] // TODO: fix this
123#[derive(Clone, Debug)]
124pub enum NodeEvent {
125  DDS(DomainParticipantStatusEvent),
126  ROS(ParticipantEntitiesInfo),
127}
128
129struct ParameterServers {
130  get_parameters_server: Server<rcl_interfaces::GetParametersService>,
131  get_parameter_types_server: Server<rcl_interfaces::GetParameterTypesService>,
132  list_parameters_server: Server<rcl_interfaces::ListParametersService>,
133  set_parameters_server: Server<rcl_interfaces::SetParametersService>,
134  set_parameters_atomically_server: Server<rcl_interfaces::SetParametersAtomicallyService>,
135  describe_parameters_server: Server<rcl_interfaces::DescribeParametersService>,
136}
137
138// ----------------------------------------------------------------------------------------------------
139// ----------------------------------------------------------------------------------------------------
140/// Spinner implements Node's background event loop.
141///
142/// At the moment there are only Discovery (DDS and ROS 2 Graph) event
143/// processing, but this would be extended to handle Parameters and other
144/// possible background tasks also.
145pub struct Spinner {
146  ros_context: Context,
147  stop_spin_receiver: async_channel::Receiver<()>,
148
149  readers_to_remote_writers: Arc<Mutex<BTreeMap<GUID, BTreeSet<GUID>>>>,
150  writers_to_remote_readers: Arc<Mutex<BTreeMap<GUID, BTreeSet<GUID>>>>,
151  // Keep track of ros_discovery_info
152  external_nodes: Arc<Mutex<BTreeMap<Gid, Vec<NodeEntitiesInfo>>>>,
153  //suppress_node_info_updates: Arc<AtomicBool>, // temporarily suppress sending updates
154  status_event_senders: Arc<Mutex<Vec<async_channel::Sender<NodeEvent>>>>,
155
156  use_sim_time: Arc<AtomicBool>,
157  sim_time: Arc<Mutex<ROSTime>>,
158  clock_topic: Topic,
159  allow_undeclared_parameters: bool,
160
161  parameter_servers: Option<ParameterServers>,
162  parameter_events_writer: Arc<Publisher<raw::ParameterEvent>>,
163  parameters: Arc<Mutex<BTreeMap<String, ParameterValue>>>,
164  parameter_validator: Option<Arc<Mutex<Box<ParameterFunc>>>>,
165  parameter_set_action: Option<Arc<Mutex<Box<ParameterFunc>>>>,
166  fully_qualified_node_name: String,
167}
168
169async fn next_if_some<S>(s: &mut Option<S>) -> S::Item
170where
171  S: Stream + Unpin + FusedStream,
172{
173  match s.as_mut() {
174    Some(stream) => stream.select_next_some().await,
175    None => std::future::pending().await,
176  }
177}
178
179impl Spinner {
180  pub async fn spin(self) -> CreateResult<()> {
181    info!("Starting Spinner for {}", self.fully_qualified_node_name);
182    let dds_status_listener = self.ros_context.domain_participant().status_listener();
183    let dds_status_stream = dds_status_listener.as_async_status_stream();
184    pin_mut!(dds_status_stream);
185
186    let ros_discovery_topic = self.ros_context.ros_discovery_topic();
187    let ros_discovery_reader = self
188      .ros_context
189      .create_subscription::<ParticipantEntitiesInfo>(&ros_discovery_topic, None)?;
190    let ros_discovery_stream = ros_discovery_reader.async_stream();
191    pin_mut!(ros_discovery_stream);
192
193    let ros_clock_reader = self
194      .ros_context
195      .create_subscription::<builtin_interfaces::Time>(&self.clock_topic, None)?;
196    let ros_clock_stream = ros_clock_reader.async_stream();
197    pin_mut!(ros_clock_stream);
198
199    // These are Option< impl Stream<_>>
200    let mut get_parameters_stream_opt = self
201      .parameter_servers
202      .as_ref()
203      .map(|s| s.get_parameters_server.receive_request_stream());
204    let mut get_parameter_types_stream_opt = self
205      .parameter_servers
206      .as_ref()
207      .map(|s| s.get_parameter_types_server.receive_request_stream());
208    let mut set_parameters_stream_opt = self
209      .parameter_servers
210      .as_ref()
211      .map(|s| s.set_parameters_server.receive_request_stream());
212    let mut set_parameters_atomically_stream_opt = self
213      .parameter_servers
214      .as_ref()
215      .map(|s| s.set_parameters_atomically_server.receive_request_stream());
216    let mut list_parameter_stream_opt = self
217      .parameter_servers
218      .as_ref()
219      .map(|s| s.list_parameters_server.receive_request_stream());
220    let mut describe_parameters_stream_opt = self
221      .parameter_servers
222      .as_ref()
223      .map(|s| s.describe_parameters_server.receive_request_stream());
224
225    info!("Spinner {} initialized", self.fully_qualified_node_name);
226
227    loop {
228      futures::select! {
229        _ = self.stop_spin_receiver.recv().fuse() => {
230          break;
231        }
232
233        clock_msg = ros_clock_stream.select_next_some() => {
234          match clock_msg {
235            Ok((time,_msg_info)) => {
236              // Simulated time is updated internally unconditionally.
237              // The logic in Node decides if it is used.
238              *self.sim_time.lock().unwrap() = time.into();
239            }
240            Err(e) => warn!("Simulated clock receive error {e:?}")
241          }
242        }
243
244
245        get_parameters_request = next_if_some(&mut get_parameters_stream_opt).fuse() => {
246          match get_parameters_request {
247            Ok( (req_id, req) ) => {
248              info!("Get parameter request {req:?}");
249              let values = {
250                let param_db = self.parameters.lock().unwrap();
251                req.names.iter()
252                  .map(|name| param_db.get(name.as_str())
253                    .unwrap_or(&ParameterValue::NotSet))
254                  .cloned()
255                  .map( raw::ParameterValue::from)
256                  .collect()
257              };
258              info!("Get parameters response: {values:?}");
259
260              // .unwrap() below should be safe, as we would not be here if the Server did not exist
261              self.parameter_servers.as_ref().unwrap().get_parameters_server
262                .async_send_response(req_id, rcl_interfaces::GetParametersResponse{ values })
263                .await
264                .unwrap_or_else(|e| warn!("GetParameter response error {e:?}"));
265            }
266            Err(e) => warn!("GetParameter request error {e:?}"),
267          }
268        }
269
270        get_parameter_types_request = next_if_some(&mut get_parameter_types_stream_opt).fuse() => {
271          match get_parameter_types_request {
272            Ok( (req_id, req) ) => {
273              warn!("Get parameter types request");
274              let values = {
275                let param_db = self.parameters.lock().unwrap();
276                req.names.iter()
277                  .map(|name| param_db.get(name.as_str())
278                    .unwrap_or(&ParameterValue::NotSet))
279                  .map(ParameterValue::to_parameter_type_raw)
280                  .collect()
281              };
282              info!("Get parameter types response: {values:?}");
283              // .unwrap() below should be safe, as we would not be here if the Server did not exist
284              self.parameter_servers.as_ref().unwrap().get_parameter_types_server
285                .async_send_response(req_id, rcl_interfaces::GetParameterTypesResponse{ values })
286                .await
287                .unwrap_or_else(|e| warn!("GetParameterTypes response error {e:?}"));
288            }
289            Err(e) => warn!("GetParameterTypes request error {e:?}"),
290          }
291        }
292
293        set_parameters_request = next_if_some(&mut set_parameters_stream_opt).fuse() => {
294          match set_parameters_request {
295            Ok( (req_id, req) ) => {
296              info!("Set parameter request {req:?}");
297              let results =
298                req.parameter.iter()
299                  .cloned()
300                  .map( Parameter::from ) // convert from "raw::Parameter"
301                  .map( |Parameter{name, value}| self.set_parameter(&name,value))
302                  .map(|r| r.into()) // to "raw" Result for serialization
303                  .collect();
304              info!("Set parameters response: {results:?}");
305              // .unwrap() below should be safe, as we would not be here if the Server did not exist
306              self.parameter_servers.as_ref().unwrap().set_parameters_server
307                .async_send_response(req_id, rcl_interfaces::SetParametersResponse{ results })
308                .await
309                .unwrap_or_else(|e| warn!("SetParameters response error {e:?}"));
310            }
311            Err(e) => warn!("SetParameters request error {e:?}"),
312          }
313        }
314
315        set_parameters_atomically_request = next_if_some(&mut set_parameters_atomically_stream_opt).fuse() => {
316          match set_parameters_atomically_request {
317            Ok( (req_id, req) ) => {
318              warn!("Set parameters atomically request {req:?}");
319              let results =
320                req.parameter.iter()
321                  .cloned()
322                  .map( Parameter::from ) // convert from "raw::Parameter"
323                  .map( |Parameter{ .. } |
324                      // TODO: Implement atomic setting.
325                      Err("Setting parameters atomically is not implemented.".to_owned())
326                    )
327                  .map(|r| r.into()) // to "raw" Result for serialization
328                  .collect();
329              warn!("Set parameters atomically response: {results:?}");
330              // .unwrap() below should be safe, as we would not be here if the Server did not exist
331              self.parameter_servers.as_ref().unwrap().set_parameters_atomically_server
332                .async_send_response(req_id, rcl_interfaces::SetParametersAtomicallyResponse{ results })
333                .await
334                .unwrap_or_else(|e| warn!("SetParameters response error {e:?}"));
335            }
336            Err(e) => warn!("SetParametersAtomically request error {e:?}"),
337          }
338        }
339
340        list_parameter_request = next_if_some(&mut list_parameter_stream_opt).fuse() => {
341          match list_parameter_request {
342            Ok( (req_id, req) ) => {
343              info!("List parameters request");
344              let prefixes = req.prefixes;
345              // TODO: We only generate the "names" part of the ListParametersResponse
346              // What should we put into `prefixes` ?
347              let names = {
348                let param_db = self.parameters.lock().unwrap();
349                param_db.keys()
350                  .filter_map(|name|
351                    if prefixes.is_empty() ||
352                      prefixes.iter().any(|prefix| name.starts_with(prefix))
353                    {
354                      Some(name.clone())
355                    } else { None }
356                  )
357                  .collect()
358              };
359              let result = rcl_interfaces::ListParametersResult{ names, prefixes: vec![] };
360              // .unwrap() below should be safe, as we would not be here if the Server did not exist
361              info!("List parameters response: {result:?}");
362              self.parameter_servers.as_ref().unwrap().list_parameters_server
363                .async_send_response(req_id, rcl_interfaces::ListParametersResponse{ result })
364                .await
365                .unwrap_or_else(|e| warn!("ListParameter response error {e:?}"));
366            }
367            Err(e) => warn!("ListParameter request error {e:?}"),
368          }
369        }
370
371        describe_parameters_request = next_if_some(&mut describe_parameters_stream_opt).fuse() => {
372          match describe_parameters_request {
373            Ok( (req_id, req) ) => {
374              info!("Describe parameters request {req:?}");
375              let values = {
376                let parameters = self.parameters.lock().unwrap();
377                req.names.iter()
378                  .map( |name|
379                    {
380                      if let Some(value) = parameters.get(name) {
381                        ParameterDescriptor::from_value(name, value)
382                      } else {
383                        ParameterDescriptor::unknown(name)
384                      }
385                    })
386                  .map(|r| r.into()) // to "raw" Result for serialization
387                  .collect()
388              };
389              info!("Describe parameters response: {values:?}");
390              // .unwrap() below should be safe, as we would not be here if the Server did not exist
391              self.parameter_servers.as_ref().unwrap().describe_parameters_server
392                .async_send_response(req_id, rcl_interfaces::DescribeParametersResponse{ values })
393                .await
394                .unwrap_or_else(|e| warn!("DescribeParameters response error {e:?}"));
395            }
396            Err(e) => warn!("DescribeParameters request error {e:?}"),
397          }
398        }
399
400        participant_info_update = ros_discovery_stream.select_next_some() => {
401          //println!("{:?}", participant_info_update);
402          match participant_info_update {
403            Ok((part_update, _msg_info)) => {
404              // insert to Node-local ros_discovery_info bookkeeping
405              let mut info_map = self.external_nodes.lock().unwrap();
406              info_map.insert( part_update.gid, part_update.node_entities_info_seq.clone());
407              // also notify any status listeneners
408              self.send_status_event( &NodeEvent::ROS(part_update) );
409            }
410            Err(e) => {
411              warn!("ros_discovery_info error {e:?}");
412            }
413          }
414        }
415
416        dp_status_event = dds_status_stream.select_next_some() => {
417          //println!("{:?}", dp_status_event );
418
419          // update remote reader/writer databases
420          match dp_status_event {
421            DomainParticipantStatusEvent::RemoteReaderMatched { local_writer, remote_reader } => {
422              self.writers_to_remote_readers.lock().unwrap()
423                .entry(local_writer)
424                .and_modify(|s| {s.insert(remote_reader);} )
425                .or_insert(BTreeSet::from([remote_reader]));
426            }
427            DomainParticipantStatusEvent::RemoteWriterMatched { local_reader, remote_writer } => {
428              self.readers_to_remote_writers.lock().unwrap()
429                .entry(local_reader)
430                .and_modify(|s| {s.insert(remote_writer);} )
431                .or_insert(BTreeSet::from([remote_writer]));
432            }
433            DomainParticipantStatusEvent::ReaderLost {guid, ..} => {
434              for readers
435              in self.writers_to_remote_readers.lock().unwrap().values_mut() {
436                readers.remove(&guid);
437              }
438            }
439            DomainParticipantStatusEvent::WriterLost {guid, ..} => {
440              for writers
441              in self.readers_to_remote_writers.lock().unwrap().values_mut() {
442                writers.remove(&guid);
443              }
444            }
445
446            _ => {}
447          }
448
449          // also notify any status listeneners
450          self.send_status_event( &NodeEvent::DDS(dp_status_event) );
451        }
452      }
453    }
454    info!("Spinner {} exiting .spin()", self.fully_qualified_node_name);
455    Ok(())
456    //}
457  } // fn
458
459  fn send_status_event(&self, event: &NodeEvent) {
460    let mut closed = Vec::new();
461    let mut sender_array = self.status_event_senders.lock().unwrap();
462    for (i, sender) in sender_array.iter().enumerate() {
463      match sender.try_send(event.clone()) {
464        Ok(()) => {
465          // expected result
466        }
467        Err(async_channel::TrySendError::Closed(_)) => {
468          // trace!("Closing {i}");
469          closed.push(i) // mark for deletion
470        }
471        Err(e) => {
472          debug!("send_status_event: Send error for {i}: {e:?}");
473          // We do not do anything about the error. It may be that the receiver
474          // is not interested and the channel is full.
475        }
476      }
477    }
478
479    // remove senders that reported they were closed
480    for c in closed.iter().rev() {
481      sender_array.swap_remove(*c);
482    }
483  }
484
485  // Keep this function in sync with the same function in Node.
486  fn validate_parameter_on_set(&self, name: &str, value: &ParameterValue) -> SetParametersResult {
487    match name {
488      // built-in parameter check
489      "use_sim_time" => match value {
490        ParameterValue::Boolean(_) => Ok(()),
491        _ => Err("Parameter'use_sim_time' must be Boolean.".to_owned()),
492      },
493      // application-defined parameters
494      _ => {
495        match self.parameter_validator {
496          Some(ref v) => v.lock().unwrap()(name, value), // ask the validator to judge
497          None => Ok(()),                                // no validator defined, always accept
498        }
499      }
500    }
501  }
502
503  // Keep this function in sync with the same function in Node.
504  fn execute_parameter_set_actions(
505    &self,
506    name: &str,
507    value: &ParameterValue,
508  ) -> SetParametersResult {
509    match name {
510      "use_sim_time" => match value {
511        ParameterValue::Boolean(s) => {
512          self.use_sim_time.store(*s, Ordering::SeqCst);
513          Ok(())
514        }
515        _ => Err("Parameter 'use_sim_time' must be Boolean.".to_owned()),
516      },
517      _ => {
518        match self.parameter_set_action {
519          Some(ref v) => v.lock().unwrap()(name, value), // execute custom action
520          None => Ok(()),                                // no action defined, always accept
521        }
522      }
523    }
524  }
525
526  /// Sets a parameter value. Parameter must be
527  /// [declared](NodeOptions::declare_parameter) before setting.
528  pub fn set_parameter(&self, name: &str, value: ParameterValue) -> Result<(), String> {
529    let already_set = self.parameters.lock().unwrap().contains_key(name);
530    if self.allow_undeclared_parameters || already_set {
531      self.validate_parameter_on_set(name, &value)?;
532      self.execute_parameter_set_actions(name, &value)?;
533
534      // no errors, prepare for sending notificaiton
535      let p = raw::Parameter {
536        name: name.to_string(),
537        value: value.clone().into(),
538      };
539      let (new_parameters, changed_parameters) = if already_set {
540        (vec![], vec![p])
541      } else {
542        (vec![p], vec![])
543      };
544
545      // actually set the parameter
546      self
547        .parameters
548        .lock()
549        .unwrap()
550        .insert(name.to_owned(), value);
551      // and notify
552      self
553        .parameter_events_writer
554        .publish(raw::ParameterEvent {
555          timestamp: rustdds::Timestamp::now(), // differs from version in Node!!!
556          node: self.fully_qualified_node_name.clone(),
557          new_parameters,
558          changed_parameters,
559          deleted_parameters: vec![],
560        })
561        .unwrap_or_else(|e| warn!("undeclare_parameter: {e:?}"));
562      Ok(())
563    } else {
564      Err("Setting undeclared parameter '".to_owned() + name + "' is not allowed.")
565    }
566  }
567} // impl Spinner
568
569// ----------------------------------------------------------------------------------------------------
570// ----------------------------------------------------------------------------------------------------
571
572/// What went wrong in `Node` creation
573#[derive(Debug)]
574pub enum NodeCreateError {
575  DDS(CreateError),
576  BadParameter(String),
577}
578
579impl From<CreateError> for NodeCreateError {
580  fn from(c: CreateError) -> NodeCreateError {
581    NodeCreateError::DDS(c)
582  }
583}
584
585impl fmt::Display for NodeCreateError {
586  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
587    match self {
588      Self::DDS(create_error) => write!(f, "NodeCreateError::DDS : {create_error}"),
589      Self::BadParameter(s) => write!(f, "NodeCreateError::BadParameter : {s}"),
590    }
591  }
592}
593
594impl Error for NodeCreateError {
595  fn source(&self) -> Option<&(dyn Error + 'static)> {
596    match self {
597      Self::DDS(create_error) => Some(create_error),
598      Self::BadParameter(_) => None,
599    }
600  }
601}
602
603/// Error when setting `Parameter`s
604pub enum ParameterError {
605  AlreadyDeclared,
606  InvalidName,
607}
608
609// TODO: We should notify ROS discovery when readers or writers are removed, but
610// now we do not do that.
611
612/// Node in ROS2 network. Holds necessary readers and writers for rosout and
613/// parameter events topics internally.
614///
615/// These are produced by a [`Context`].
616///
617/// Many ROS 2 background tasks do not run unless you execute a [`Spinner`] for
618/// a `Node`. If you are using an async executor, consider running e.g.
619/// `
620/// smol::spawn(node.spinner().unwrap().spin()).detach();
621/// `
622pub struct Node {
623  node_name: NodeName,
624  options: NodeOptions,
625
626  pub(crate) ros_context: Context,
627
628  // sets of Readers and Writers belonging to ( = created via) this Node
629  // These indicate what has been created locally.
630  readers: BTreeSet<Gid>,
631  writers: BTreeSet<Gid>,
632
633  suppress_node_info_updates: Arc<AtomicBool>,
634  // temporarily suppress sending updates
635  // to prevent flood of messages. TODO: not shared: need not be atomic or Arc.
636
637  // Keep track of who is matched via DDS Discovery
638  // Map keys are lists of local Subscriptions and Publishers.
639  // Map values are lists of matched Publishers / Subscriptions.
640  readers_to_remote_writers: Arc<Mutex<BTreeMap<GUID, BTreeSet<GUID>>>>,
641  writers_to_remote_readers: Arc<Mutex<BTreeMap<GUID, BTreeSet<GUID>>>>,
642
643  // Keep track of ros_discovery_info
644  external_nodes: Arc<Mutex<BTreeMap<Gid, Vec<NodeEntitiesInfo>>>>,
645  stop_spin_sender: Option<async_channel::Sender<()>>,
646
647  // Channels to report discovery events to
648  status_event_senders: Arc<Mutex<Vec<async_channel::Sender<NodeEvent>>>>,
649
650  // builtin writers and readers
651  rosout_writer: Arc<Option<Publisher<Log>>>,
652  rosout_reader: Option<Subscription<Log>>,
653
654  // Parameter events (rcl_interfaces)
655  // Parameter Services are inside Spinner
656  parameter_events_writer: Arc<Publisher<raw::ParameterEvent>>,
657
658  // Parameter store
659  parameters: Arc<Mutex<BTreeMap<String, ParameterValue>>>,
660  // allow_undeclared_parameters: bool, // this is inside "options"
661  parameter_validator: Option<Arc<Mutex<Box<ParameterFunc>>>>,
662  parameter_set_action: Option<Arc<Mutex<Box<ParameterFunc>>>>,
663
664  // simulated ROSTime
665  use_sim_time: Arc<AtomicBool>,
666  sim_time: Arc<Mutex<ROSTime>>,
667}
668
669impl Node {
670  pub(crate) fn new(
671    node_name: NodeName,
672    mut options: NodeOptions,
673    ros_context: Context,
674  ) -> Result<Node, NodeCreateError> {
675    let paramtopic = ros_context.get_parameter_events_topic();
676    let rosout_topic = ros_context.get_rosout_topic();
677
678    let enable_rosout = options.enable_rosout;
679    let rosout_reader = options.enable_rosout_reading;
680
681    let parameter_events_writer = ros_context.create_publisher(&paramtopic, None)?;
682
683    // TODO: If there are duplicates, the later one will overwrite the earlier, but
684    // there is no warning or error.
685    options.declared_parameters.push(Parameter {
686      name: "use_sim_time".to_string(),
687      value: ParameterValue::Boolean(false),
688    });
689    let parameters = options
690      .declared_parameters
691      .iter()
692      .cloned()
693      .map(|Parameter { name, value }| (name, value))
694      .collect::<BTreeMap<String, ParameterValue>>();
695
696    let parameter_validator = options
697      .parameter_validator
698      .take()
699      .map(|b| Arc::new(Mutex::new(b)));
700    let parameter_set_action = options
701      .parameter_set_action
702      .take()
703      .map(|b| Arc::new(Mutex::new(b)));
704
705    let mut node = Node {
706      node_name,
707      options,
708      ros_context,
709      readers: BTreeSet::new(),
710      writers: BTreeSet::new(),
711      readers_to_remote_writers: Arc::new(Mutex::new(BTreeMap::new())),
712      writers_to_remote_readers: Arc::new(Mutex::new(BTreeMap::new())),
713      external_nodes: Arc::new(Mutex::new(BTreeMap::new())),
714      suppress_node_info_updates: Arc::new(AtomicBool::new(false)),
715      stop_spin_sender: None,
716      status_event_senders: Arc::new(Mutex::new(Vec::new())),
717      rosout_writer: Arc::new(None), // Set below
718      rosout_reader: None,
719      parameter_events_writer: Arc::new(parameter_events_writer),
720      parameters: Arc::new(Mutex::new(parameters)),
721      parameter_validator,
722      parameter_set_action,
723      use_sim_time: Arc::new(AtomicBool::new(false)),
724      sim_time: Arc::new(Mutex::new(ROSTime::ZERO)),
725    };
726
727    node.suppress_node_info_updates(true);
728
729    node.rosout_writer = if enable_rosout {
730      Arc::new(Some(
731        // topic already has QoS defined
732        node.create_publisher(&rosout_topic, None)?,
733      ))
734    } else {
735      Arc::new(None) // FIXME: we already set that above!
736    };
737    node.rosout_reader = if rosout_reader {
738      Some(node.create_subscription(&rosout_topic, None)?)
739    } else {
740      None
741    };
742
743    // returns `Err` if some parameter does not validate.
744    node
745      .parameters
746      .lock()
747      .unwrap()
748      .iter()
749      .try_for_each(|(name, value)| {
750        node.validate_parameter_on_set(name, value)?;
751        node.execute_parameter_set_actions(name, value)?;
752        Ok(())
753      })
754      .map_err(NodeCreateError::BadParameter)?;
755
756    node.suppress_node_info_updates(false);
757
758    Ok(node)
759  }
760
761  /// Return the ROSTime
762  ///
763  /// It is either the system clock time
764  pub fn time_now(&self) -> ROSTime {
765    if self.use_sim_time.load(Ordering::SeqCst) {
766      *self.sim_time.lock().unwrap()
767    } else {
768      ROSTime::now()
769    }
770  }
771
772  pub fn time_now_not_simulated(&self) -> ROSTime {
773    ROSTime::now()
774  }
775
776  /// Create a Spinner object to execute Node backround tasks.
777  ///
778  /// An async task should then be created to run the `.spin()` function of
779  /// `Spinner`.
780  ///
781  /// E.g. `executor.spawn(node.spinner().spin())`
782  ///
783  /// The `.spin()` task runs until `Node` is dropped.
784  pub fn spinner(&mut self) -> CreateResult<Spinner> {
785    if self.stop_spin_sender.is_some() {
786      panic!("Attempted to crate a second spinner.");
787    }
788    let (stop_spin_sender, stop_spin_receiver) = async_channel::bounded(1);
789    self.stop_spin_sender = Some(stop_spin_sender);
790
791    //TODO: Check QoS policies against ROS 2 specs or some refernce.
792    let service_qos = QosPolicyBuilder::new()
793      .reliability(policy::Reliability::Reliable {
794        max_blocking_time: Duration::from_millis(100),
795      })
796      .history(policy::History::KeepLast { depth: 1 })
797      .build();
798
799    let node_name = self.node_name.fully_qualified_name();
800
801    self.suppress_node_info_updates(true);
802
803    let parameter_servers = if self.options.start_parameter_services {
804      let service_mapping = ServiceMapping::Enhanced; //TODO: parameterize
805      let get_parameters_server = self.create_server(
806        service_mapping,
807        &Name::new(&node_name, "get_parameters").unwrap(),
808        &ServiceTypeName::new("rcl_interfaces", "GetParameters"),
809        service_qos.clone(),
810        service_qos.clone(),
811      )?;
812      let get_parameter_types_server = self.create_server(
813        service_mapping,
814        &Name::new(&node_name, "get_parameter_types").unwrap(),
815        &ServiceTypeName::new("rcl_interfaces", "GetParameterTypes"),
816        service_qos.clone(),
817        service_qos.clone(),
818      )?;
819      let set_parameters_server = self.create_server(
820        service_mapping,
821        &Name::new(&node_name, "set_parameters").unwrap(),
822        &ServiceTypeName::new("rcl_interfaces", "SetParameters"),
823        service_qos.clone(),
824        service_qos.clone(),
825      )?;
826      let set_parameters_atomically_server = self.create_server(
827        service_mapping,
828        &Name::new(&node_name, "set_parameters_atomically").unwrap(),
829        &ServiceTypeName::new("rcl_interfaces", "SetParametersAtomically"),
830        service_qos.clone(),
831        service_qos.clone(),
832      )?;
833      let list_parameters_server = self.create_server(
834        service_mapping,
835        &Name::new(&node_name, "list_parameters").unwrap(),
836        &ServiceTypeName::new("rcl_interfaces", "ListParameters"),
837        service_qos.clone(),
838        service_qos.clone(),
839      )?;
840      let describe_parameters_server = self.create_server(
841        service_mapping,
842        &Name::new(&node_name, "describe_parameters").unwrap(),
843        &ServiceTypeName::new("rcl_interfaces", "DescribeParameters"),
844        service_qos.clone(),
845        service_qos.clone(),
846      )?;
847
848      Some(ParameterServers {
849        get_parameters_server,
850        get_parameter_types_server,
851        list_parameters_server,
852        set_parameters_server,
853        set_parameters_atomically_server,
854        describe_parameters_server,
855      })
856    } else {
857      None // No parameter services
858    };
859
860    let clock_topic = self.create_topic(
861      &Name::new("/", "clock").unwrap(),
862      MessageTypeName::new("builtin_interfaces", "Time"),
863      &DEFAULT_SUBSCRIPTION_QOS,
864    )?;
865
866    self.suppress_node_info_updates(false);
867
868    Ok(Spinner {
869      ros_context: self.ros_context.clone(),
870      stop_spin_receiver,
871      readers_to_remote_writers: Arc::clone(&self.readers_to_remote_writers),
872      writers_to_remote_readers: Arc::clone(&self.writers_to_remote_readers),
873      external_nodes: Arc::clone(&self.external_nodes),
874      status_event_senders: Arc::clone(&self.status_event_senders),
875      use_sim_time: Arc::clone(&self.use_sim_time),
876      sim_time: Arc::clone(&self.sim_time),
877      clock_topic,
878      parameter_servers,
879      parameter_events_writer: Arc::clone(&self.parameter_events_writer),
880      parameters: Arc::clone(&self.parameters),
881      allow_undeclared_parameters: self.options.allow_undeclared_parameters,
882      parameter_validator: self.parameter_validator.as_ref().map(Arc::clone),
883      parameter_set_action: self.parameter_set_action.as_ref().map(Arc::clone),
884      fully_qualified_node_name: self.fully_qualified_name(),
885    })
886  }
887
888  /// A heuristic to detect if a spinner has been created.
889  /// But this does still not guarantee that it is running, i.e.
890  /// an async excutor is runnning spinner.spin(), but this is the best we can
891  /// do.
892  pub fn have_spinner(&self) -> bool {
893    self.stop_spin_sender.is_some()
894  }
895
896  // Generates ROS2 node info from added readers and writers.
897  fn generate_node_info(&self) -> NodeEntitiesInfo {
898    let mut node_info = NodeEntitiesInfo::new(self.node_name.clone());
899
900    node_info.add_writer(Gid::from(self.parameter_events_writer.guid()));
901    if let Some(ref row) = *self.rosout_writer {
902      node_info.add_writer(Gid::from(row.guid()));
903    }
904
905    for reader in &self.readers {
906      node_info.add_reader(*reader);
907    }
908
909    for writer in &self.writers {
910      node_info.add_writer(*writer);
911    }
912
913    node_info
914  }
915
916  fn suppress_node_info_updates(&mut self, suppress: bool) {
917    self
918      .suppress_node_info_updates
919      .store(suppress, Ordering::SeqCst);
920
921    // Send updates when suppression ends
922    if !suppress {
923      self.ros_context.update_node(self.generate_node_info());
924    }
925  }
926
927  fn add_reader(&mut self, reader: Gid) {
928    self.readers.insert(reader);
929    if !self.suppress_node_info_updates.load(Ordering::SeqCst) {
930      self.ros_context.update_node(self.generate_node_info());
931    }
932  }
933
934  fn add_writer(&mut self, writer: Gid) {
935    self.writers.insert(writer);
936    if !self.suppress_node_info_updates.load(Ordering::SeqCst) {
937      self.ros_context.update_node(self.generate_node_info());
938    }
939  }
940
941  pub fn namespace(&self) -> &str {
942    self.node_name.namespace()
943  }
944
945  pub fn fully_qualified_name(&self) -> String {
946    self.node_name.fully_qualified_name()
947  }
948
949  pub fn options(&self) -> &NodeOptions {
950    &self.options
951  }
952
953  pub fn domain_id(&self) -> u16 {
954    self.ros_context.domain_id()
955  }
956
957  // ///////////////////////////////////////////////
958  // Parameters
959
960  pub fn undeclare_parameter(&self, name: &str) {
961    let prev_value = self.parameters.lock().unwrap().remove(name);
962
963    if let Some(deleted_param) = prev_value {
964      // a parameter was actually undeclared. Let others know.
965      self
966        .parameter_events_writer
967        .publish(raw::ParameterEvent {
968          timestamp: self.time_now().into(),
969          node: self.fully_qualified_name(),
970          new_parameters: vec![],
971          changed_parameters: vec![],
972          deleted_parameters: vec![raw::Parameter {
973            name: name.to_string(),
974            value: deleted_param.into(),
975          }],
976        })
977        .unwrap_or_else(|e| warn!("undeclare_parameter: {e:?}"));
978    }
979  }
980
981  /// Does the parameter exist?
982  pub fn has_parameter(&self, name: &str) -> bool {
983    self.parameters.lock().unwrap().contains_key(name)
984  }
985
986  /// Sets a parameter value. Parameter must be
987  /// [declared](NodeOptions::declare_parameter) before setting.
988  //
989  // TODO: This code is duplicated in Spinner. Not good.
990  // Find a way to de-duplicate.
991  // Same for validate_parameter_on_set and execute_parameter_set_actions.
992  // TODO: This does not account for built-in parameters e.g. "use_sim_time".
993  // It thinks they are new on first set.
994  // TODO: Setting Parameter to type NotSet counts as parameter deletion. Maybe
995  // that needs special handling? At least for notifications.
996  pub fn set_parameter(&self, name: &str, value: ParameterValue) -> Result<(), String> {
997    let already_set = self.parameters.lock().unwrap().contains_key(name);
998    if self.options.allow_undeclared_parameters || already_set {
999      self.validate_parameter_on_set(name, &value)?;
1000      self.execute_parameter_set_actions(name, &value)?;
1001
1002      // no errors, prepare for sending notificaiton
1003      let p = raw::Parameter {
1004        name: name.to_string(),
1005        value: value.clone().into(),
1006      };
1007      let (new_parameters, changed_parameters) = if already_set {
1008        (vec![], vec![p])
1009      } else {
1010        (vec![p], vec![])
1011      };
1012
1013      // actually set the parameter
1014      self
1015        .parameters
1016        .lock()
1017        .unwrap()
1018        .insert(name.to_owned(), value);
1019      // and notify
1020      self
1021        .parameter_events_writer
1022        .publish(raw::ParameterEvent {
1023          timestamp: self.time_now().into(),
1024          node: self.fully_qualified_name(),
1025          new_parameters,
1026          changed_parameters,
1027          deleted_parameters: vec![],
1028        })
1029        .unwrap_or_else(|e| warn!("undeclare_parameter: {e:?}"));
1030      Ok(())
1031    } else {
1032      Err("Setting undeclared parameter '".to_owned() + name + "' is not allowed.")
1033    }
1034  }
1035
1036  pub fn allow_undeclared_parameters(&self) -> bool {
1037    self.options.allow_undeclared_parameters
1038  }
1039
1040  /// Gets the value of a parameter, or None is there is no such Parameter.
1041  pub fn get_parameter(&self, name: &str) -> Option<ParameterValue> {
1042    self
1043      .parameters
1044      .lock()
1045      .unwrap()
1046      .get(name)
1047      .map(|p| p.to_owned())
1048  }
1049
1050  pub fn list_parameters(&self) -> Vec<String> {
1051    self
1052      .parameters
1053      .lock()
1054      .unwrap()
1055      .keys()
1056      .map(move |k| k.to_owned())
1057      .collect::<Vec<_>>()
1058  }
1059
1060  // Keep this function in sync with the same function in Spinner.
1061  // TODO: This should refuse to change parameter type, unless
1062  // there is a ParamaterDescription defined and it allows
1063  // changing type.
1064  // TODO: Setting Parameter to type NotSet counts as parameter deletion. Maybe
1065  // that needs special handling?
1066  fn validate_parameter_on_set(&self, name: &str, value: &ParameterValue) -> SetParametersResult {
1067    match name {
1068      // built-in parameter check
1069      "use_sim_time" => match value {
1070        ParameterValue::Boolean(_) => Ok(()),
1071        _ => Err("Parameter'use_sim_time' must be Boolean.".to_owned()),
1072      },
1073      // application-defined parameters
1074      _ => {
1075        match self.parameter_validator {
1076          Some(ref v) => v.lock().unwrap()(name, value), // ask the validator to judge
1077          None => Ok(()),                                // no validator defined, always accept
1078        }
1079      }
1080    }
1081  }
1082
1083  // Keep this function in sync with the same function in Spinner.
1084  fn execute_parameter_set_actions(
1085    &self,
1086    name: &str,
1087    value: &ParameterValue,
1088  ) -> SetParametersResult {
1089    match name {
1090      "use_sim_time" => match value {
1091        ParameterValue::Boolean(s) => {
1092          self.use_sim_time.store(*s, Ordering::SeqCst);
1093          Ok(())
1094        }
1095        _ => Err("Parameter 'use_sim_time' must be Boolean.".to_owned()),
1096      },
1097      _ => {
1098        match self.parameter_set_action {
1099          Some(ref v) => v.lock().unwrap()(name, value), // execute custom action
1100          None => Ok(()),                                // no action defined, always accept
1101        }
1102      }
1103    }
1104  }
1105
1106  // ///////////////////////////////////////////////////
1107
1108  /// Get an async Receiver for discovery events.
1109  ///
1110  /// There must be an async task executing `spin` to get any data.
1111  /// This function may panic if there is no Spinner running.
1112  pub fn status_receiver(&self) -> Receiver<NodeEvent> {
1113    if self.have_spinner() {
1114      let (status_event_sender, status_event_receiver) = async_channel::bounded(8);
1115      self
1116        .status_event_senders
1117        .lock()
1118        .unwrap()
1119        .push(status_event_sender);
1120      status_event_receiver
1121    } else {
1122      panic!("status_receiver() cannot set up a receiver, because no Spinner is running.")
1123    }
1124  }
1125
1126  // reader waits for at least one writer to be present
1127  pub(crate) fn wait_for_writer(&self, reader: GUID) -> impl Future<Output = ()> {
1128    // TODO: This may contain some synchrnoization hazard
1129    let status_receiver = self.status_receiver();
1130
1131    let already_present = self
1132      .readers_to_remote_writers
1133      .lock()
1134      .unwrap()
1135      .get(&reader)
1136      .map(|writers| !writers.is_empty()) // there is someone matched
1137      .unwrap_or(false); // we do not even know the reader
1138
1139    if already_present {
1140      WriterWait::Ready
1141    } else {
1142      WriterWait::Wait {
1143        this_reader: reader,
1144        status_event_stream: Box::pin(status_receiver),
1145      }
1146    }
1147  }
1148
1149  pub(crate) fn wait_for_reader(&self, writer: GUID) -> impl Future<Output = ()> {
1150    // TODO: This may contain some synchrnoization hazard.
1151    let status_receiver = self.status_receiver();
1152
1153    let already_present = self
1154      .writers_to_remote_readers
1155      .lock()
1156      .unwrap()
1157      .get(&writer)
1158      .map(|readers| !readers.is_empty()) // there is someone matched
1159      .unwrap_or(false); // we do not even know who is asking
1160
1161    // TODO: Is is possible to miss reader events if they appear after the check
1162    // above, but do not somehow end up in the status_receiver stream?
1163
1164    if already_present {
1165      info!("wait_for_reader: Already have matched a reader.");
1166      ReaderWait::Ready
1167    } else {
1168      ReaderWait::Wait {
1169        this_writer: writer,
1170        status_event_stream: Box::pin(status_receiver),
1171      }
1172    }
1173  }
1174
1175  pub(crate) fn get_publisher_count(&self, subscription_guid: GUID) -> usize {
1176    self
1177      .readers_to_remote_writers
1178      .lock()
1179      .unwrap()
1180      .get(&subscription_guid)
1181      .map(BTreeSet::len)
1182      .unwrap_or_else(|| {
1183        error!("get_publisher_count: Subscriber {subscription_guid:?} not known to node.");
1184        0
1185      })
1186  }
1187
1188  pub(crate) fn get_subscription_count(&self, publisher_guid: GUID) -> usize {
1189    self
1190      .writers_to_remote_readers
1191      .lock()
1192      .unwrap()
1193      .get(&publisher_guid)
1194      .map(BTreeSet::len)
1195      .unwrap_or_else(|| {
1196        error!("get_subscription_count: Publisher {publisher_guid:?} not known to node.");
1197        0
1198      })
1199  }
1200
1201  /// Borrow the Subscription to our ROSOut Reader.
1202  ///
1203  /// Availability depends on Node configuration.
1204  pub fn rosout_subscription(&self) -> Option<&Subscription<Log>> {
1205    self.rosout_reader.as_ref()
1206  }
1207
1208  /// Creates ROS2 topic and handles necessary conversions from DDS to ROS2
1209  ///
1210  /// # Arguments
1211  ///
1212  /// * `domain_participant` -
1213  ///   [DomainParticipant](../dds/struct.DomainParticipant.html)
1214  /// * `name` - Name of the topic
1215  /// * `type_name` - What type the topic holds in string form
1216  /// * `qos` - Quality of Service parameters for the topic (not restricted only
1217  ///   to ROS2)
1218  ///
1219  ///  
1220  ///   [summary of all rules for topic and service names in ROS 2](https://design.ros2.org/articles/topic_and_service_names.html)
1221  ///   (as of Dec 2020)
1222  ///
1223  /// * must not be empty
1224  /// * may contain alphanumeric characters ([0-9|a-z|A-Z]), underscores (_), or
1225  ///   forward slashes (/)
1226  /// * may use balanced curly braces ({}) for substitutions
1227  /// * may start with a tilde (~), the private namespace substitution character
1228  /// * must not start with a numeric character ([0-9])
1229  /// * must not end with a forward slash (/)
1230  /// * must not contain any number of repeated forward slashes (/)
1231  /// * must not contain any number of repeated underscores (_)
1232  /// * must separate a tilde (~) from the rest of the name with a forward slash
1233  ///   (/), i.e. ~/foo not ~foo
1234  /// * must have balanced curly braces ({}) when used, i.e. {sub}/foo but not
1235  ///   {sub/foo nor /foo}
1236  pub fn create_topic(
1237    &self,
1238    topic_name: &Name,
1239    type_name: MessageTypeName,
1240    qos: &QosPolicies,
1241  ) -> CreateResult<Topic> {
1242    let dds_name = topic_name.to_dds_name("rt", &self.node_name, "");
1243    self.ros_context.create_topic(dds_name, type_name, qos)
1244  }
1245
1246  /// Creates ROS2 Subscriber
1247  ///
1248  /// # Arguments
1249  ///
1250  /// * `topic` - Reference to topic created with `create_ros_topic`.
1251  /// * `qos` - Should take [QOS](../dds/qos/struct.QosPolicies.html) and use if
1252  ///   it's compatible with topics QOS. `None` indicates the use of Topics QOS.
1253  pub fn create_subscription<D: 'static>(
1254    &mut self,
1255    topic: &Topic,
1256    qos: Option<QosPolicies>,
1257  ) -> CreateResult<Subscription<D>> {
1258    let sub = self.ros_context.create_subscription(topic, qos)?;
1259    self.add_reader(sub.guid().into());
1260    Ok(sub)
1261  }
1262
1263  /// Creates ROS2 Publisher
1264  ///
1265  /// # Arguments
1266  ///
1267  /// * `topic` - Reference to topic created with `create_ros_topic`.
1268  /// * `qos` - Should take [QOS](../dds/qos/struct.QosPolicies.html) and use it
1269  ///   if it's compatible with topics QOS. `None` indicates the use of Topics
1270  ///   QOS.
1271  pub fn create_publisher<D: Serialize>(
1272    &mut self,
1273    topic: &Topic,
1274    qos: Option<QosPolicies>,
1275  ) -> CreateResult<Publisher<D>> {
1276    let p = self.ros_context.create_publisher(topic, qos)?;
1277    self.add_writer(p.guid().into());
1278    Ok(p)
1279  }
1280
1281  pub(crate) fn create_simpledatareader<D, DA>(
1282    &mut self,
1283    topic: &Topic,
1284    qos: Option<QosPolicies>,
1285  ) -> CreateResult<no_key::SimpleDataReader<D, DA>>
1286  where
1287    D: 'static,
1288    DA: rustdds::no_key::DeserializerAdapter<D> + 'static,
1289  {
1290    let r = self.ros_context.create_simpledatareader(topic, qos)?;
1291    self.add_reader(r.guid().into());
1292    Ok(r)
1293  }
1294
1295  pub(crate) fn create_datawriter<D, SA>(
1296    &mut self,
1297    topic: &Topic,
1298    qos: Option<QosPolicies>,
1299  ) -> CreateResult<no_key::DataWriter<D, SA>>
1300  where
1301    SA: rustdds::no_key::SerializerAdapter<D>,
1302  {
1303    let w = self.ros_context.create_datawriter(topic, qos)?;
1304    self.add_writer(w.guid().into());
1305    Ok(w)
1306  }
1307
1308  /// Creates ROS2 Service Client
1309  ///
1310  /// # Arguments
1311  ///
1312  /// * `service_mapping` - ServiceMapping to be used
1313  /// * `service_name` -
1314  /// * `qos`-
1315  pub fn create_client<S>(
1316    &mut self,
1317    service_mapping: ServiceMapping,
1318    service_name: &Name,
1319    service_type_name: &ServiceTypeName,
1320    request_qos: QosPolicies,
1321    response_qos: QosPolicies,
1322  ) -> CreateResult<Client<S>>
1323  where
1324    S: Service + 'static,
1325    S::Request: Clone,
1326  {
1327    // Add rq/ and rr/ prefixes as documented in
1328    // https://design.ros2.org/articles/topic_and_service_names.html
1329    // Where are the suffixes documented?
1330    // And why "Reply" and not "Response" ?
1331
1332    let rq_topic = self.ros_context.domain_participant().create_topic(
1333      service_name.to_dds_name("rq", &self.node_name, "Request"),
1334      //rq_name,
1335      service_type_name.dds_request_type(),
1336      &request_qos,
1337      TopicKind::NoKey,
1338    )?;
1339    let rs_topic = self.ros_context.domain_participant().create_topic(
1340      service_name.to_dds_name("rr", &self.node_name, "Reply"),
1341      //rs_name,
1342      service_type_name.dds_response_type(),
1343      &response_qos,
1344      TopicKind::NoKey,
1345    )?;
1346
1347    let c = Client::<S>::new(
1348      service_mapping,
1349      self,
1350      &rq_topic,
1351      &rs_topic,
1352      Some(request_qos),
1353      Some(response_qos),
1354    )?;
1355
1356    Ok(c)
1357  }
1358
1359  /// Creates ROS2 Service Server
1360  ///
1361  /// # Arguments
1362  ///
1363  /// * `service_mapping` - ServiceMapping to be used. See
1364  ///   [`Self::create_client`].
1365  /// * `service_name` -
1366  /// * `qos`-
1367  pub fn create_server<S>(
1368    &mut self,
1369    service_mapping: ServiceMapping,
1370    service_name: &Name,
1371    service_type_name: &ServiceTypeName,
1372    request_qos: QosPolicies,
1373    response_qos: QosPolicies,
1374  ) -> CreateResult<Server<S>>
1375  where
1376    S: Service + 'static,
1377    S::Request: Clone,
1378  {
1379    // let rq_name = Self::check_name_and_add_prefix("rq/",
1380    // &(service_name.to_owned() + "Request"))?; let rs_name =
1381    // Self::check_name_and_add_prefix("rr/", &(service_name.to_owned() +
1382    // "Reply"))?;
1383
1384    let rq_topic = self.ros_context.domain_participant().create_topic(
1385      //rq_name,
1386      service_name.to_dds_name("rq", &self.node_name, "Request"),
1387      service_type_name.dds_request_type(),
1388      &request_qos,
1389      TopicKind::NoKey,
1390    )?;
1391    let rs_topic = self.ros_context.domain_participant().create_topic(
1392      service_name.to_dds_name("rr", &self.node_name, "Reply"),
1393      service_type_name.dds_response_type(),
1394      &response_qos,
1395      TopicKind::NoKey,
1396    )?;
1397
1398    let s = Server::<S>::new(
1399      service_mapping,
1400      self,
1401      &rq_topic,
1402      &rs_topic,
1403      Some(request_qos),
1404      Some(response_qos),
1405    )?;
1406
1407    Ok(s)
1408  }
1409
1410  pub fn create_action_client<A>(
1411    &mut self,
1412    service_mapping: ServiceMapping,
1413    action_name: &Name,
1414    action_type_name: &ActionTypeName,
1415    action_qos: ActionClientQosPolicies,
1416  ) -> CreateResult<ActionClient<A>>
1417  where
1418    A: ActionTypes + 'static,
1419  {
1420    // action name is e.g. "/turtle1/rotate_absolute"
1421    // action type name is e.g. "turtlesim/action/RotateAbsolute"
1422    let services_base_name = action_name.push("_action");
1423
1424    //let goal_service_name = action_name.to_owned() + "/_action/send_goal";
1425    let goal_service_type = action_type_name.dds_action_service("_SendGoal");
1426    let my_goal_client = self.create_client(
1427      service_mapping,
1428      //&goal_service_name,
1429      &services_base_name.push("send_goal"),
1430      &goal_service_type,
1431      action_qos.goal_service.clone(),
1432      action_qos.goal_service,
1433    )?;
1434
1435    //let cancel_service_name = action_name.to_owned() + "/_action/cancel_goal";
1436    let cancel_goal_type = ServiceTypeName::new("action_msgs", "CancelGoal");
1437    let my_cancel_client = self.create_client(
1438      service_mapping,
1439      //&cancel_service_name,
1440      &services_base_name.push("cancel_goal"),
1441      &cancel_goal_type,
1442      action_qos.cancel_service.clone(),
1443      action_qos.cancel_service,
1444    )?;
1445
1446    //let result_service_name = action_name.to_owned() + "/_action/get_result";
1447    let result_service_type = action_type_name.dds_action_service("_GetResult");
1448    let my_result_client = self.create_client(
1449      service_mapping,
1450      //&result_service_name,
1451      &services_base_name.push("get_result"),
1452      &result_service_type,
1453      action_qos.result_service.clone(),
1454      action_qos.result_service,
1455    )?;
1456
1457    let action_topic_namespace = action_name.push("_action");
1458
1459    let feedback_topic_type = action_type_name.dds_action_topic("_FeedbackMessage");
1460    let feedback_topic = self.create_topic(
1461      &action_topic_namespace.push("feedback"),
1462      feedback_topic_type,
1463      &action_qos.feedback_subscription,
1464    )?;
1465    let my_feedback_subscription =
1466      self.create_subscription(&feedback_topic, Some(action_qos.feedback_subscription))?;
1467
1468    //let status_topic_type = ;
1469    let status_topic = self.create_topic(
1470      &action_topic_namespace.push("status"),
1471      MessageTypeName::new("action_msgs", "GoalStatusArray"),
1472      &action_qos.status_subscription,
1473    )?;
1474    let my_status_subscription =
1475      self.create_subscription(&status_topic, Some(action_qos.status_subscription))?;
1476
1477    Ok(ActionClient {
1478      my_goal_client,
1479      my_cancel_client,
1480      my_result_client,
1481      my_feedback_subscription,
1482      my_status_subscription,
1483      my_action_name: action_name.clone(),
1484    })
1485  }
1486
1487  pub fn create_action_server<A>(
1488    &mut self,
1489    service_mapping: ServiceMapping,
1490    action_name: &Name,
1491    action_type_name: &ActionTypeName,
1492    action_qos: ActionServerQosPolicies,
1493  ) -> CreateResult<ActionServer<A>>
1494  where
1495    A: ActionTypes + 'static,
1496  {
1497    let services_base_name = action_name.push("_action");
1498
1499    //let goal_service_name = action_name.to_owned() + "/_action/send_goal";
1500    let goal_service_type = action_type_name.dds_action_service("_SendGoal");
1501    let my_goal_server = self.create_server(
1502      service_mapping,
1503      //&goal_service_name,
1504      &services_base_name.push("send_goal"),
1505      &goal_service_type,
1506      action_qos.goal_service.clone(),
1507      action_qos.goal_service,
1508    )?;
1509
1510    //let cancel_service_name = action_name.to_owned() + "/_action/cancel_goal";
1511    let cancel_service_type = ServiceTypeName::new("action_msgs", "CancelGoal");
1512    let my_cancel_server = self.create_server(
1513      service_mapping,
1514      //&cancel_service_name,
1515      &services_base_name.push("cancel_goal"),
1516      &cancel_service_type,
1517      action_qos.cancel_service.clone(),
1518      action_qos.cancel_service,
1519    )?;
1520
1521    //let result_service_name = action_name.to_owned() + "/_action/get_result";
1522    let result_service_type = action_type_name.dds_action_service("_GetResult");
1523    let my_result_server = self.create_server(
1524      service_mapping,
1525      //&result_service_name,
1526      &services_base_name.push("get_result"),
1527      &result_service_type,
1528      action_qos.result_service.clone(),
1529      action_qos.result_service,
1530    )?;
1531
1532    let action_topic_namespace = action_name.push("_action");
1533
1534    let feedback_topic_type = action_type_name.dds_action_topic("_FeedbackMessage");
1535    let feedback_topic = self.create_topic(
1536      &action_topic_namespace.push("feedback"),
1537      feedback_topic_type,
1538      &action_qos.feedback_publisher,
1539    )?;
1540    let my_feedback_publisher =
1541      self.create_publisher(&feedback_topic, Some(action_qos.feedback_publisher))?;
1542
1543    let status_topic_type = MessageTypeName::new("action_msgs", "GoalStatusArray");
1544    let status_topic = self.create_topic(
1545      &action_topic_namespace.push("status"),
1546      status_topic_type,
1547      &action_qos.status_publisher,
1548    )?;
1549    let my_status_publisher =
1550      self.create_publisher(&status_topic, Some(action_qos.status_publisher))?;
1551
1552    Ok(ActionServer {
1553      my_goal_server,
1554      my_cancel_server,
1555      my_result_server,
1556      my_feedback_publisher,
1557      my_status_publisher,
1558      my_action_name: action_name.clone(),
1559    })
1560  }
1561
1562  /// Makes a handle to the `rosout` logging publisher.
1563  ///
1564  /// You can send these across threads
1565  pub fn logging_handle(&self) -> NodeLoggingHandle {
1566    NodeLoggingHandle {
1567      rosout_writer: Arc::clone(&self.rosout_writer),
1568      base_name: self.node_name.base_name().to_string(),
1569    }
1570  }
1571
1572  pub fn stop_spinner(&self) {
1573    info!("Signalling spinner to stop (manual)");
1574    if let Some(ref stop_spin_sender) = self.stop_spin_sender {
1575      stop_spin_sender
1576        .try_send(())
1577        .unwrap_or_else(|e| error!("Cannot notify spin task to stop: {e:?}"));
1578    }
1579  }
1580} // impl Node
1581
1582impl Drop for Node {
1583  fn drop(&mut self) {
1584    debug!("Signalling spinner to stop (.drop)");
1585    if let Some(ref stop_spin_sender) = self.stop_spin_sender {
1586      stop_spin_sender
1587        .try_send(())
1588        .unwrap_or_else(|e| error!("Cannot notify spin task to stop: {e:?}"));
1589    }
1590
1591    self
1592      .ros_context
1593      .remove_node(self.fully_qualified_name().as_str());
1594  }
1595}
1596
1597impl RosoutRaw for Node {
1598  fn rosout_writer(&self) -> Arc<Option<Publisher<Log>>> {
1599    Arc::clone(&self.rosout_writer)
1600  }
1601
1602  fn base_name(&self) -> &str {
1603    self.node_name.base_name()
1604  }
1605}
1606
1607/// Macro for writing to [rosout](https://wiki.ros.org/rosout) topic.
1608///
1609/// # Example
1610///
1611/// ```
1612/// # use ros2_client::*;
1613/// #
1614/// # let context = Context::new().unwrap();
1615/// # let mut node = context
1616/// #     .new_node(
1617/// #       NodeName::new("/", "some_node").unwrap(),
1618/// #       NodeOptions::new().enable_rosout(true),
1619/// #     )
1620/// #     .unwrap();
1621/// let kind = "silly";
1622///
1623/// rosout!(node, ros2::LogLevel::Info, "A {} event was seen.", kind);
1624/// ```
1625#[macro_export]
1626macro_rules! rosout {
1627    ($node:expr, $lvl:expr, $($arg:tt)+) => (
1628        $crate::rosout::RosoutRaw::rosout_raw(
1629            &$node,
1630            $crate::ros2::Timestamp::now(),
1631            $lvl,
1632            $crate::rosout::RosoutRaw::base_name(&$node),
1633            &std::format!($($arg)+), // msg
1634            std::file!(),
1635            "<unknown_func>", // is there a macro to get current function name? (Which may be undefined)
1636            std::line!(),
1637        );
1638    );
1639}
1640
1641/// Future type for waiting Readers to appear over ROS2 Topic.
1642///
1643/// Produced by `node.wait_for_reader(writer_guid)`
1644//
1645// This is implemented as a separate struct instead of just async function in
1646// Node so that it does not borrow the node and thus can be Send.
1647//use pin_project::pin_project;
1648#[must_use = "futures do nothing unless you `.await` or poll them"]
1649pub enum ReaderWait<'a> {
1650  // We need to wait for an event that is for us
1651  Wait {
1652    this_writer: GUID, // Writer who is waiting for Readers to appear
1653    status_event_stream: stream::BoxStream<'a, NodeEvent>,
1654  },
1655  // No need to wait, can resolve immediately.
1656  Ready,
1657}
1658
1659impl Future for ReaderWait<'_> {
1660  type Output = ();
1661
1662  fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
1663    match *self {
1664      ReaderWait::Ready => Poll::Ready(()),
1665
1666      ReaderWait::Wait {
1667        this_writer,
1668        ref mut status_event_stream,
1669      } => {
1670        debug!("wait_for_reader: Waiting for a reader.");
1671        loop {
1672          match status_event_stream.poll_next_unpin(cx) {
1673            // Check if we have RemoteReaderMatched event and it is for this_writer
1674            Poll::Ready(Some(NodeEvent::DDS(
1675              DomainParticipantStatusEvent::RemoteReaderMatched {
1676                local_writer,
1677                remote_reader,
1678              },
1679            )))
1680              if local_writer == this_writer =>
1681            {
1682              debug!("wait_for_reader: Matched remote reader {remote_reader:?}.");
1683              return Poll::Ready(());
1684            }
1685
1686            Poll::Ready(_) => {
1687              // Received something else, such as other event or error
1688              debug!("wait_for_reader: other event. Continue polling.");
1689              // So we do nothing but go to the next iteration.
1690            }
1691
1692            Poll::Pending => return Poll::Pending,
1693          }
1694        }
1695      }
1696    }
1697  }
1698}
1699
1700/// Future type for waiting Writers to appear over ROS2 Topic.
1701///
1702/// Produced by `node.wait_for_writer(writer_guid)`
1703//
1704// This is implemented as a separate struct instead of just async function in
1705// Node so that it does not borrow the node and thus can be Send.
1706#[must_use = "futures do nothing unless you `.await` or poll them"]
1707pub enum WriterWait<'a> {
1708  // We need to wait for an event that is for us
1709  Wait {
1710    this_reader: GUID,
1711    status_event_stream: stream::BoxStream<'a, NodeEvent>,
1712  },
1713  // No need to wait, can resolve immediately.
1714  Ready,
1715}
1716
1717impl Future for WriterWait<'_> {
1718  type Output = ();
1719
1720  fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
1721    match *self {
1722      WriterWait::Ready => Poll::Ready(()),
1723
1724      WriterWait::Wait {
1725        this_reader,
1726        ref mut status_event_stream,
1727      } => {
1728        debug!("wait_for_writer: Waiting for a writer.");
1729        loop {
1730          // We loop to pump events out of the stream until we get the desired event
1731          // or "Pending". If we stop at the first event, then there is no waker
1732          // installed and we are stuck.
1733          match status_event_stream.poll_next_unpin(cx) {
1734            // Check if we have RemoteWriterMatched event and it is for this_writer
1735            Poll::Ready(Some(NodeEvent::DDS(
1736              DomainParticipantStatusEvent::RemoteWriterMatched {
1737                local_reader,
1738                remote_writer,
1739              },
1740            )))
1741              if local_reader == this_reader =>
1742            {
1743              debug!("wait_for_writer: Matched remote writer {remote_writer:?}.");
1744              return Poll::Ready(());
1745            }
1746
1747            Poll::Ready(_) => {
1748              // Received something else, such as other event or error
1749              trace!("=== other writer. Continue polling.");
1750              // No return, go to next iteration.
1751            }
1752
1753            Poll::Pending => return Poll::Pending,
1754          }
1755        }
1756      }
1757    }
1758  }
1759}
1760
1761#[cfg(test)]
1762mod tests {
1763  use crate::Context;
1764  use super::{Node, NodeName, NodeOptions};
1765
1766  #[test]
1767  fn node_is_sync() {
1768    let node = Node::new(
1769      NodeName::new("/", "base_name").unwrap(),
1770      NodeOptions::new(),
1771      Context::new().unwrap(),
1772    )
1773    .unwrap();
1774
1775    fn requires_send_sync<T: Send + Sync>(_t: T) {}
1776    requires_send_sync(node);
1777  }
1778}