zbus_macros: generated Proxy::new() method is sometimes misleading
This ticket is based on a prior conversation at https://github.com/lucab/zbus_systemd/issues/6.
The #[dbus_proxy]
macro logic has the following templated code:
impl<'c> #proxy_name<'c> {
/// Creates a new proxy with the default service & path.
pub #usage fn new(conn: &#connection) -> #zbus::Result<#proxy_name<'c>> {
Self::builder(conn).build()#wait
}
}
This generates a FooProxy::new()
method which assumes that both "default service" and "default path" for a proxy have meaningful values.
But that is not always the case, for example when default_service
or default_path
attributes are not specified.
We hit this when working with systemd DBus API, here is a reduced reproducer:
use zbus::dbus_proxy;
#[dbus_proxy(
interface = "org.freedesktop.systemd1.Service",
gen_blocking = false,
default_service = "org.freedesktop.systemd1"
)]
trait Service {
#[dbus_proxy(property, name = "MainPID")]
fn main_pid(&self) -> zbus::Result<u32>;
}
type ExResult<T> = Result<T, Box<dyn std::error::Error + 'static>>;
fn main() {
let rt = tokio::runtime::Runtime::new().unwrap();
let ret = rt.block_on(run());
if let Err(e) = ret {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}
async fn run() -> ExResult<()> {
let conn = zbus::Connection::system().await?;
{
let path = "/org/freedesktop/systemd1/unit/systemd_2djournald_2eservice";
let service = ServiceProxy::builder(&conn).path(path)?.build().await?;
let main_pid = service.main_pid().await?;
println!("Service main PID: {}", main_pid);
}
{
let service = ServiceProxy::new(&conn).await?;
let main_pid = service.main_pid().await?;
println!("Service main PID: {}", main_pid);
}
Ok(())
}
Running this example will result in the following output:
Service main PID: 497
Error: org.freedesktop.DBus.Error.UnknownObject: Unknown object '/org/freedesktop/Service'.
The first line shows that the current way to properly use the generated proxy is through the builder()
flow, which is a bit verbose and not ergonomic.
The second line shows that the generated new()
method is misleading: it will point to a synthetic /org/freedesktop/Service
path, which does not really exist. In fact, this Service
interface only exists on individual units, not a as a singleton. For this reason, there is no default_path
attribute specified on the macro.