zbus/blocking/proxy/
mod.rs

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