Attribute Macro zbus::dbus_proxy
source · #[dbus_proxy]
Expand description
Attribute macro for defining D-Bus proxies (using zbus::Proxy
and
zbus::blocking::Proxy
).
The macro must be applied on a trait T
. Two matching impl T
will provide an asynchronous
Proxy implementation, named TraitNameProxy
and a blocking one, named TraitNameProxyBlocking
.
The proxy instances can be created with the associated new()
or builder()
methods. The
former doesn’t take any argument and uses the default service name and path. The later allows
you to specify non-default proxy arguments.
The following attributes are supported:
-
interface
- the name of the D-Bus interface this proxy is for. -
default_service
- the default service this proxy should connect to. -
default_path
- The default object path the method calls will be sent on and signals will be sent for by the target service. -
gen_async
- Whether or not to generate the asynchronous Proxy type. -
gen_blocking
- Whether or not to generate the blocking Proxy type. If set tofalse
, the asynchronous proxy type will take the nameTraitNameProxy
(i-e noAsync
prefix). -
async_name
- Specify the exact name of the asynchronous proxy type. -
blocking_name
- Specify the exact name of the blocking proxy type. -
assume_defaults
- whether to auto-generate values fordefault_path
anddefault_service
if none are specified (default:true
).dbus_proxy
currently generates a warning if neither this attribute nor one of the default values are specified. A future release will change the default tofalse
. Please make sure to explicitly set either this attribute or the default values, according to your needs.
Each trait method will be expanded to call to the associated D-Bus remote interface.
Trait methods accept dbus_proxy
attributes:
-
name
- override the D-Bus name (pascal case form by default) -
property
- expose the method as a property. If the method takes an argument, it must be a setter, with aset_
prefix. Otherwise, it’s a getter. Additional sub-attributes exists to control specific property behaviors:emits_changed_signal
- specifies how property changes are signaled. Valid values are those documented in DBus specifications:"true"
- (default) change signal is always emitted with the value included. This uses the default caching behavior of the proxy, and generates a listener method for the change signal."invalidates"
- change signal is emitted, but the value is not included in the signal. This has the same behavior as"true"
."const"
- property never changes, thus no signal is ever emitted for it. This uses the default caching behavior of the proxy, but does not generate a listener method for the change signal."false"
- change signal is not (guaranteed to be) emitted if the property changes. This disables property value caching, and does not generate a listener method for the change signal.
-
signal
- declare a signal just like a D-Bus method. Read the Signals section below for details. -
no_reply
- declare a method call that does not wait for a reply. -
no_autostart
- declare a method call that will not trigger the bus to automatically launch the destination service if it is not already running. -
allow_interactive_auth
- declare a method call that is allowed to trigger an interactive prompt for authorization or confirmation from the receiver. -
object
- methods that returns anObjectPath
can be annotated with theobject
attribute to specify the proxy object to be constructed from the returnedObjectPath
. -
async_object
- if the assumptions made byobject
attribute about naming of the asynchronous proxy type, don’t fit your bill, you can use this to specify its exact name. -
blocking_object
- if the assumptions made byobject
attribute about naming of the blocking proxy type, don’t fit your bill, you can use this to specify its exact name.NB: Any doc comments provided shall be appended to the ones added by the macro.
§Signals
For each signal method declared, this macro will provide a method, named receive_<method_name>
to create a zbus::SignalStream
(zbus::blocking::SignalIterator
for the blocking proxy)
wrapper, named <SignalName>Stream
(<SignalName>Iterator
for the blocking proxy) that yield
a zbus::Message
wrapper, named <SignalName>
. This wrapper provides type safe access to the
signal arguments. It also implements Deref<Target = Message>
to allow easy access to the
underlying zbus::Message
.
§Example
use zbus_macros::dbus_proxy;
use zbus::{blocking::Connection, Result, fdo, zvariant::Value};
use futures_util::stream::StreamExt;
use async_io::block_on;
#[dbus_proxy(
interface = "org.test.SomeIface",
default_service = "org.test.SomeService",
default_path = "/org/test/SomeObject"
)]
trait SomeIface {
fn do_this(&self, with: &str, some: u32, arg: &Value<'_>) -> Result<bool>;
#[dbus_proxy(property)]
fn a_property(&self) -> fdo::Result<String>;
#[dbus_proxy(property)]
fn set_a_property(&self, a_property: &str) -> fdo::Result<()>;
#[dbus_proxy(signal)]
fn some_signal(&self, arg1: &str, arg2: u32) -> fdo::Result<()>;
#[dbus_proxy(object = "SomeOtherIface", blocking_object = "SomeOtherInterfaceBlock")]
// The method will return a `SomeOtherIfaceProxy` or `SomeOtherIfaceProxyBlock`, depending
// on whether it is called on `SomeIfaceProxy` or `SomeIfaceProxyBlocking`, respectively.
//
// NB: We explicitly specified the exact name of the blocking proxy type. If we hadn't,
// `SomeOtherIfaceProxyBlock` would have been assumed and expected. We could also specify
// the specific name of the asynchronous proxy types, using the `async_object` attribute.
fn some_method(&self, arg1: &str);
}
#[dbus_proxy(
interface = "org.test.SomeOtherIface",
default_service = "org.test.SomeOtherService",
blocking_name = "SomeOtherInterfaceBlock",
)]
trait SomeOtherIface {}
let connection = Connection::session()?;
// Use `builder` to override the default arguments, `new` otherwise.
let proxy = SomeIfaceProxyBlocking::builder(&connection)
.destination("org.another.Service")?
.cache_properties(zbus::CacheProperties::No)
.build()?;
let _ = proxy.do_this("foo", 32, &Value::new(true));
let _ = proxy.set_a_property("val");
let signal = proxy.receive_some_signal()?.next().unwrap();
let args = signal.args()?;
println!("arg1: {}, arg2: {}", args.arg1(), args.arg2());
// Now the same again, but asynchronous.
block_on(async move {
let proxy = SomeIfaceProxy::builder(&connection.into())
.cache_properties(zbus::CacheProperties::No)
.build()
.await
.unwrap();
let _ = proxy.do_this("foo", 32, &Value::new(true)).await;
let _ = proxy.set_a_property("val").await;
let signal = proxy.receive_some_signal().await?.next().await.unwrap();
let args = signal.args()?;
println!("arg1: {}, arg2: {}", args.arg1(), args.arg2());
Ok::<(), zbus::Error>(())
})?;
zbus_polkit
is a good example of how to bind a real D-Bus API.