Skip to main content

motorcortex_rust/blocking/
request.rs

1//! Blocking wrapper around [`crate::core::Request`].
2
3use std::sync::{Arc, RwLock};
4
5use tokio::runtime::Runtime;
6
7use crate::client::ParameterTree;
8use crate::connection::ConnectionOptions;
9use crate::core;
10use crate::error::{MotorcortexError, Result};
11use crate::msg::{GroupStatusMsg, StatusCode};
12use crate::parameter_value::{
13    GetParameterTuple, GetParameterValue, SetParameterTuple, SetParameterValue,
14};
15
16/// Blocking analogue of [`core::Request`]. Every method mirrors the
17/// async one without the `.await`. The hidden current-thread runtime
18/// runs the await internally.
19///
20/// `Request` is `!Sync` because the `Runtime` it owns is; clone one
21/// via [`new`](Self::new) per thread that needs independent blocking
22/// access, or use the async API if you need `Sync`.
23pub struct Request {
24    inner: core::Request,
25    pub(crate) rt: Arc<Runtime>,
26}
27
28impl Request {
29    /// Create a new handle. Spawns the async driver thread and
30    /// allocates a single-threaded tokio runtime to drive its
31    /// futures to completion.
32    pub fn new() -> Result<Self> {
33        let rt = tokio::runtime::Builder::new_current_thread()
34            .enable_all()
35            .build()
36            .map_err(|e| MotorcortexError::Connection(e.to_string()))?;
37        Ok(Self {
38            inner: core::Request::new(),
39            rt: Arc::new(rt),
40        })
41    }
42
43    /// Construct + connect in one call.
44    ///
45    /// ```no_run
46    /// use motorcortex_rust::{ConnectionOptions, blocking::Request};
47    /// # fn demo() -> motorcortex_rust::Result<()> {
48    /// let opts = ConnectionOptions::new("mcx.cert.crt".into(), 1000, 1000);
49    /// let req = Request::connect_to("wss://127.0.0.1:5568", opts)?;
50    /// req.request_parameter_tree()?;
51    /// let v: f64 = req.get_parameter("root/Control/dummyDouble")?;
52    /// println!("{v}");
53    /// # Ok(()) }
54    /// ```
55    pub fn connect_to(url: &str, opts: ConnectionOptions) -> Result<Self> {
56        let request = Self::new()?;
57        request.connect(url, opts)?;
58        Ok(request)
59    }
60
61    pub fn connect(&self, url: &str, opts: ConnectionOptions) -> Result<()> {
62        self.rt.block_on(self.inner.connect(url, opts))
63    }
64
65    pub fn disconnect(&self) -> Result<()> {
66        self.rt.block_on(self.inner.disconnect())
67    }
68
69    pub fn login(&self, user: &str, pass: &str) -> Result<StatusCode> {
70        self.rt.block_on(self.inner.login(user, pass))
71    }
72
73    pub fn logout(&self) -> Result<StatusCode> {
74        self.rt.block_on(self.inner.logout())
75    }
76
77    pub fn request_parameter_tree(&self) -> Result<StatusCode> {
78        self.rt.block_on(self.inner.request_parameter_tree())
79    }
80
81    pub fn get_parameter_tree_hash(&self) -> Result<u32> {
82        self.rt.block_on(self.inner.get_parameter_tree_hash())
83    }
84
85    pub fn get_parameter<V>(&self, path: &str) -> Result<V>
86    where
87        V: GetParameterValue + Default,
88    {
89        self.rt.block_on(self.inner.get_parameter(path))
90    }
91
92    pub fn set_parameter<V>(&self, path: &str, value: V) -> Result<StatusCode>
93    where
94        V: SetParameterValue,
95    {
96        self.rt.block_on(self.inner.set_parameter(path, value))
97    }
98
99    pub fn get_parameters<T>(&self, paths: &[&str]) -> Result<T>
100    where
101        T: GetParameterTuple,
102    {
103        self.rt.block_on(self.inner.get_parameters(paths))
104    }
105
106    pub fn set_parameters<T>(&self, paths: &[&str], values: T) -> Result<StatusCode>
107    where
108        T: SetParameterTuple,
109    {
110        self.rt.block_on(self.inner.set_parameters(paths, values))
111    }
112
113    pub fn create_group<I>(
114        &self,
115        paths: I,
116        alias: &str,
117        fdiv: u32,
118    ) -> Result<GroupStatusMsg>
119    where
120        I: crate::client::Parameters,
121    {
122        self.rt.block_on(self.inner.create_group(paths, alias, fdiv))
123    }
124
125    pub fn remove_group(&self, alias: &str) -> Result<StatusCode> {
126        self.rt.block_on(self.inner.remove_group(alias))
127    }
128
129    /// Shared parameter-tree cache. Populated by
130    /// [`request_parameter_tree`](Self::request_parameter_tree).
131    pub fn parameter_tree(&self) -> Arc<RwLock<ParameterTree>> {
132        self.inner.parameter_tree()
133    }
134
135    /// Access the inner async handle — useful when one part of your
136    /// program is blocking and another is async.
137    pub fn as_async(&self) -> &core::Request {
138        &self.inner
139    }
140}