zbus/blocking/
proxy.rs

1use enumflags2::BitFlags;
2use futures_util::StreamExt;
3use static_assertions::assert_impl_all;
4use std::{
5    convert::{TryFrom, TryInto},
6    ops::Deref,
7    sync::Arc,
8};
9use zbus_names::{BusName, InterfaceName, MemberName, UniqueName};
10use zvariant::{ObjectPath, OwnedValue, Value};
11
12use crate::{blocking::Connection, utils::block_on, Error, Message, MethodFlags, Result};
13
14use crate::fdo;
15
16/// A blocking wrapper of [`crate::Proxy`].
17///
18/// This API is mostly the same as [`crate::Proxy`], except that all its methods block to
19/// completion.
20///
21/// # Example
22///
23/// ```
24/// use std::result::Result;
25/// use std::error::Error;
26/// use zbus::blocking::{Connection, Proxy};
27///
28/// fn main() -> Result<(), Box<dyn Error>> {
29///     let connection = Connection::session()?;
30///     let p = Proxy::new(
31///         &connection,
32///         "org.freedesktop.DBus",
33///         "/org/freedesktop/DBus",
34///         "org.freedesktop.DBus",
35///     )?;
36///     // owned return value
37///     let _id: String = p.call("GetId", &())?;
38///     // borrowed return value
39///     let _id: &str = p.call_method("GetId", &())?.body()?;
40///     Ok(())
41/// }
42/// ```
43///
44/// # Note
45///
46/// It is recommended to use the [`dbus_proxy`] macro, which provides a more convenient and
47/// type-safe *façade* `Proxy` derived from a Rust trait.
48///
49/// ## Current limitations:
50///
51/// At the moment, `Proxy` doesn't prevent [auto-launching][al].
52///
53/// [`dbus_proxy`]: attr.dbus_proxy.html
54/// [al]: https://github.com/dbus2/zbus/issues/54
55#[derive(derivative::Derivative)]
56#[derivative(Clone, Debug)]
57pub struct Proxy<'a> {
58    #[derivative(Debug = "ignore")]
59    conn: Connection,
60    // Wrap it in an `Option` to ensure the proxy is dropped in a `block_on` call. This is needed
61    // for tokio because the proxy spawns a task in its `Drop` impl and that needs a runtime
62    // context in case of tokio.
63    azync: Option<crate::Proxy<'a>>,
64}
65
66assert_impl_all!(Proxy<'_>: Send, Sync, Unpin);
67
68impl<'a> Proxy<'a> {
69    /// Create a new `Proxy` for the given destination/path/interface.
70    pub fn new<D, P, I>(
71        conn: &Connection,
72        destination: D,
73        path: P,
74        interface: I,
75    ) -> Result<Proxy<'a>>
76    where
77        D: TryInto<BusName<'a>>,
78        P: TryInto<ObjectPath<'a>>,
79        I: TryInto<InterfaceName<'a>>,
80        D::Error: Into<Error>,
81        P::Error: Into<Error>,
82        I::Error: Into<Error>,
83    {
84        let proxy = block_on(crate::Proxy::new(
85            conn.inner(),
86            destination,
87            path,
88            interface,
89        ))?;
90
91        Ok(Self {
92            conn: conn.clone(),
93            azync: Some(proxy),
94        })
95    }
96
97    /// Create a new `Proxy` for the given destination/path/interface, taking ownership of all
98    /// passed arguments.
99    pub fn new_owned<D, P, I>(
100        conn: Connection,
101        destination: D,
102        path: P,
103        interface: I,
104    ) -> Result<Proxy<'a>>
105    where
106        D: TryInto<BusName<'static>>,
107        P: TryInto<ObjectPath<'static>>,
108        I: TryInto<InterfaceName<'static>>,
109        D::Error: Into<Error>,
110        P::Error: Into<Error>,
111        I::Error: Into<Error>,
112    {
113        let proxy = block_on(crate::Proxy::new_owned(
114            conn.clone().into_inner(),
115            destination,
116            path,
117            interface,
118        ))?;
119
120        Ok(Self {
121            conn,
122            azync: Some(proxy),
123        })
124    }
125
126    /// Get a reference to the associated connection.
127    pub fn connection(&self) -> &Connection {
128        &self.conn
129    }
130
131    /// Get a reference to the destination service name.
132    pub fn destination(&self) -> &BusName<'_> {
133        self.inner().destination()
134    }
135
136    /// Get a reference to the object path.
137    pub fn path(&self) -> &ObjectPath<'_> {
138        self.inner().path()
139    }
140
141    /// Get a reference to the interface.
142    pub fn interface(&self) -> &InterfaceName<'_> {
143        self.inner().interface()
144    }
145
146    /// Introspect the associated object, and return the XML description.
147    ///
148    /// See the [xml](xml/index.html) module for parsing the result.
149    pub fn introspect(&self) -> fdo::Result<String> {
150        block_on(self.inner().introspect())
151    }
152
153    /// Get the cached value of the property `property_name`.
154    ///
155    /// This returns `None` if the property is not in the cache.  This could be because the cache
156    /// was invalidated by an update, because caching was disabled for this property or proxy, or
157    /// because the cache has not yet been populated.  Use `get_property` to fetch the value from
158    /// the peer.
159    pub fn cached_property<T>(&self, property_name: &str) -> Result<Option<T>>
160    where
161        T: TryFrom<OwnedValue>,
162        T::Error: Into<Error>,
163    {
164        self.inner().cached_property(property_name)
165    }
166
167    /// Get the cached value of the property `property_name`.
168    ///
169    /// Same as `cached_property`, but gives you access to the raw value stored in the cache. This
170    /// is useful if you want to avoid allocations and cloning.
171    pub fn cached_property_raw<'p>(
172        &'p self,
173        property_name: &'p str,
174    ) -> Option<impl Deref<Target = Value<'static>> + 'p> {
175        self.inner().cached_property_raw(property_name)
176    }
177
178    /// Get the property `property_name`.
179    ///
180    /// Get the property value from the cache or call the `Get` method of the
181    /// `org.freedesktop.DBus.Properties` interface.
182    pub fn get_property<T>(&self, property_name: &str) -> Result<T>
183    where
184        T: TryFrom<OwnedValue>,
185        T::Error: Into<Error>,
186    {
187        block_on(self.inner().get_property(property_name))
188    }
189
190    /// Set the property `property_name`.
191    ///
192    /// Effectively, call the `Set` method of the `org.freedesktop.DBus.Properties` interface.
193    pub fn set_property<'t, T: 't>(&self, property_name: &str, value: T) -> fdo::Result<()>
194    where
195        T: Into<Value<'t>>,
196    {
197        block_on(self.inner().set_property(property_name, value))
198    }
199
200    /// Call a method and return the reply.
201    ///
202    /// Typically, you would want to use [`call`] method instead. Use this method if you need to
203    /// deserialize the reply message manually (this way, you can avoid the memory
204    /// allocation/copying, by deserializing the reply to an unowned type).
205    ///
206    /// [`call`]: struct.Proxy.html#method.call
207    pub fn call_method<'m, M, B>(&self, method_name: M, body: &B) -> Result<Arc<Message>>
208    where
209        M: TryInto<MemberName<'m>>,
210        M::Error: Into<Error>,
211        B: serde::ser::Serialize + zvariant::DynamicType,
212    {
213        block_on(self.inner().call_method(method_name, body))
214    }
215
216    /// Call a method and return the reply body.
217    ///
218    /// Use [`call_method`] instead if you need to deserialize the reply manually/separately.
219    ///
220    /// [`call_method`]: struct.Proxy.html#method.call_method
221    pub fn call<'m, M, B, R>(&self, method_name: M, body: &B) -> Result<R>
222    where
223        M: TryInto<MemberName<'m>>,
224        M::Error: Into<Error>,
225        B: serde::ser::Serialize + zvariant::DynamicType,
226        R: serde::de::DeserializeOwned + zvariant::Type,
227    {
228        block_on(self.inner().call(method_name, body))
229    }
230
231    /// Call a method and return the reply body, optionally supplying a set of
232    /// method flags to control the way the method call message is sent and handled.
233    ///
234    /// Use [`call`] instead if you do not need any special handling via additional flags.
235    /// If the `NoReplyExpected` flag is passed , this will return None immediately
236    /// after sending the message, similar to [`call_noreply`]
237    ///
238    /// [`call`]: struct.Proxy.html#method.call
239    /// [`call_noreply`]: struct.Proxy.html#method.call_noreply
240    pub fn call_with_flags<'m, M, B, R>(
241        &self,
242        method_name: M,
243        flags: BitFlags<MethodFlags>,
244        body: &B,
245    ) -> Result<Option<R>>
246    where
247        M: TryInto<MemberName<'m>>,
248        M::Error: Into<Error>,
249        B: serde::ser::Serialize + zvariant::DynamicType,
250        R: serde::de::DeserializeOwned + zvariant::Type,
251    {
252        block_on(self.inner().call_with_flags(method_name, flags, body))
253    }
254
255    /// Call a method without expecting a reply
256    ///
257    /// This sets the `NoReplyExpected` flag on the calling message and does not wait for a reply.
258    pub fn call_noreply<'m, M, B>(&self, method_name: M, body: &B) -> Result<()>
259    where
260        M: TryInto<MemberName<'m>>,
261        M::Error: Into<Error>,
262        B: serde::ser::Serialize + zvariant::DynamicType,
263    {
264        block_on(self.inner().call_noreply(method_name, body))
265    }
266
267    /// Create a stream for signal named `signal_name`.
268    ///
269    /// # Errors
270    ///
271    /// Apart from general I/O errors that can result from socket communications, calling this
272    /// method will also result in an error if the destination service has not yet registered its
273    /// well-known name with the bus (assuming you're using the well-known name as destination).
274    pub fn receive_signal<'m, M>(&self, signal_name: M) -> Result<SignalIterator<'m>>
275    where
276        M: TryInto<MemberName<'m>>,
277        M::Error: Into<Error>,
278    {
279        self.receive_signal_with_args(signal_name, &[])
280    }
281
282    /// Same as [`Proxy::receive_signal`] but with a filter.
283    ///
284    /// The D-Bus specification allows you to filter signals by their arguments, which helps avoid
285    /// a lot of unnecessary traffic and processing since the filter is run on the server side. Use
286    /// this method where possible. Note that this filtering is limited to arguments of string
287    /// types.
288    ///
289    /// The arguments are passed as a tuples of argument index and expected value.
290    pub fn receive_signal_with_args<'m, M>(
291        &self,
292        signal_name: M,
293        args: &[(u8, &str)],
294    ) -> Result<SignalIterator<'m>>
295    where
296        M: TryInto<MemberName<'m>>,
297        M::Error: Into<Error>,
298    {
299        block_on(self.inner().receive_signal_with_args(signal_name, args))
300            .map(Some)
301            .map(SignalIterator)
302    }
303
304    /// Create a stream for all signals emitted by this service.
305    ///
306    /// # Errors
307    ///
308    /// Apart from general I/O errors that can result from socket communications, calling this
309    /// method will also result in an error if the destination service has not yet registered its
310    /// well-known name with the bus (assuming you're using the well-known name as destination).
311    pub fn receive_all_signals(&self) -> Result<SignalIterator<'static>> {
312        block_on(self.inner().receive_all_signals())
313            .map(Some)
314            .map(SignalIterator)
315    }
316
317    /// Get an iterator to receive owner changed events.
318    ///
319    /// If the proxy destination is a unique name, the stream will be notified of the peer
320    /// disconnection from the bus (with a `None` value).
321    ///
322    /// If the proxy destination is a well-known name, the stream will be notified whenever the name
323    /// owner is changed, either by a new peer being granted ownership (`Some` value) or when the
324    /// name is released (with a `None` value).
325    ///
326    /// Note that zbus doesn't queue the updates. If the listener is slower than the receiver, it
327    /// will only receive the last update.
328    pub fn receive_property_changed<'name: 'a, T>(
329        &self,
330        name: &'name str,
331    ) -> PropertyIterator<'a, T> {
332        PropertyIterator(block_on(self.inner().receive_property_changed(name)))
333    }
334
335    /// Get an iterator to receive property changed events.
336    ///
337    /// Note that zbus doesn't queue the updates. If the listener is slower than the receiver, it
338    /// will only receive the last update.
339    pub fn receive_owner_changed(&self) -> Result<OwnerChangedIterator<'_>> {
340        block_on(self.inner().receive_owner_changed()).map(OwnerChangedIterator)
341    }
342
343    /// Get a reference to the underlying async Proxy.
344    pub fn inner(&self) -> &crate::Proxy<'a> {
345        self.azync.as_ref().expect("Inner proxy is `None`")
346    }
347
348    /// Get the underlying async Proxy, consuming `self`.
349    pub fn into_inner(mut self) -> crate::Proxy<'a> {
350        self.azync.take().expect("Inner proxy is `None`")
351    }
352}
353
354impl<'a> std::convert::AsRef<Proxy<'a>> for Proxy<'a> {
355    fn as_ref(&self) -> &Proxy<'a> {
356        self
357    }
358}
359
360impl<'a> From<crate::Proxy<'a>> for Proxy<'a> {
361    fn from(proxy: crate::Proxy<'a>) -> Self {
362        Self {
363            conn: proxy.connection().clone().into(),
364            azync: Some(proxy),
365        }
366    }
367}
368
369impl std::ops::Drop for Proxy<'_> {
370    fn drop(&mut self) {
371        block_on(async {
372            self.azync.take();
373        });
374    }
375}
376
377/// An [`std::iter::Iterator`] implementation that yields signal [messages](`Message`).
378///
379/// Use [`Proxy::receive_signal`] to create an instance of this type.
380#[derive(Debug)]
381pub struct SignalIterator<'a>(Option<crate::SignalStream<'a>>);
382
383impl<'a> SignalIterator<'a> {
384    /// The signal name.
385    pub fn name(&self) -> Option<&MemberName<'a>> {
386        self.0.as_ref().expect("`SignalStream` is `None`").name()
387    }
388}
389
390assert_impl_all!(SignalIterator<'_>: Send, Sync, Unpin);
391
392impl std::iter::Iterator for SignalIterator<'_> {
393    type Item = Arc<Message>;
394
395    fn next(&mut self) -> Option<Self::Item> {
396        block_on(self.0.as_mut().expect("`SignalStream` is `None`").next())
397    }
398}
399
400impl std::ops::Drop for SignalIterator<'_> {
401    fn drop(&mut self) {
402        block_on(async {
403            if let Some(azync) = self.0.take() {
404                crate::AsyncDrop::async_drop(azync).await;
405            }
406        });
407    }
408}
409
410/// An [`std::iter::Iterator`] implementation that yields property change notifications.
411///
412/// Use [`Proxy::receive_property_changed`] to create an instance of this type.
413pub struct PropertyIterator<'a, T>(crate::PropertyStream<'a, T>);
414
415impl<'a, T> std::iter::Iterator for PropertyIterator<'a, T>
416where
417    T: Unpin,
418{
419    type Item = PropertyChanged<'a, T>;
420
421    fn next(&mut self) -> Option<Self::Item> {
422        block_on(self.0.next()).map(PropertyChanged)
423    }
424}
425
426/// A property changed event.
427///
428/// The property changed event generated by [`PropertyIterator`].
429pub struct PropertyChanged<'a, T>(crate::PropertyChanged<'a, T>);
430
431// split this out to avoid the trait bound on `name` method
432impl<'a, T> PropertyChanged<'a, T> {
433    /// Get the name of the property that changed.
434    pub fn name(&self) -> &str {
435        self.0.name()
436    }
437
438    // Get the raw value of the property that changed.
439    //
440    // If the notification signal contained the new value, it has been cached already and this call
441    // will return that value. Otherwise (i-e invalidated property), a D-Bus call is made to fetch
442    // and cache the new value.
443    pub fn get_raw(&self) -> Result<impl Deref<Target = Value<'static>> + '_> {
444        block_on(self.0.get_raw())
445    }
446}
447
448impl<'a, T> PropertyChanged<'a, T>
449where
450    T: TryFrom<zvariant::OwnedValue>,
451    T::Error: Into<crate::Error>,
452{
453    // Get the value of the property that changed.
454    //
455    // If the notification signal contained the new value, it has been cached already and this call
456    // will return that value. Otherwise (i-e invalidated property), a D-Bus call is made to fetch
457    // and cache the new value.
458    pub fn get(&self) -> Result<T> {
459        block_on(self.0.get())
460    }
461}
462
463/// An [`std::iter::Iterator`] implementation that yields owner change notifications.
464///
465/// Use [`Proxy::receive_owner_changed`] to create an instance of this type.
466pub struct OwnerChangedIterator<'a>(crate::OwnerChangedStream<'a>);
467
468impl OwnerChangedIterator<'_> {
469    /// The bus name being tracked.
470    pub fn name(&self) -> &BusName<'_> {
471        self.0.name()
472    }
473}
474
475impl<'a> std::iter::Iterator for OwnerChangedIterator<'a> {
476    type Item = Option<UniqueName<'static>>;
477
478    fn next(&mut self) -> Option<Self::Item> {
479        block_on(self.0.next())
480    }
481}
482
483#[cfg(test)]
484mod tests {
485    use super::*;
486    use crate::blocking;
487    use ntest::timeout;
488    use test_log::test;
489
490    #[test]
491    #[timeout(15000)]
492    fn signal() {
493        // Register a well-known name with the session bus and ensure we get the appropriate
494        // signals called for that.
495        let conn = Connection::session().unwrap();
496        let unique_name = conn.unique_name().unwrap().to_string();
497
498        let proxy = blocking::fdo::DBusProxy::new(&conn).unwrap();
499        let well_known = "org.freedesktop.zbus.ProxySignalTest";
500        let mut owner_changed = proxy
501            .receive_name_owner_changed_with_args(&[(0, well_known), (2, unique_name.as_str())])
502            .unwrap();
503        let mut name_acquired = proxy
504            .receive_name_acquired_with_args(&[(0, well_known)])
505            .unwrap();
506
507        blocking::fdo::DBusProxy::new(&conn)
508            .unwrap()
509            .request_name(
510                well_known.try_into().unwrap(),
511                fdo::RequestNameFlags::ReplaceExisting.into(),
512            )
513            .unwrap();
514
515        let signal = owner_changed.next().unwrap();
516        let args = signal.args().unwrap();
517        assert!(args.name() == well_known);
518        assert!(*args.new_owner().as_ref().unwrap() == *unique_name);
519
520        let signal = name_acquired.next().unwrap();
521        // `NameAcquired` is emitted twice, first when the unique name is assigned on
522        // connection and secondly after we ask for a specific name. Let's make sure we only get the
523        // one we subscribed to.
524        assert!(signal.args().unwrap().name() == well_known);
525    }
526}