Skip to main content

zbus/fdo/
object_manager.rs

1//! D-Bus standard interfaces.
2//!
3//! The D-Bus specification defines the message bus messages and some standard interfaces that may
4//! be useful across various D-Bus applications. This module provides their proxy.
5
6use std::{borrow::Cow, collections::HashMap};
7use zbus_names::{InterfaceName, OwnedInterfaceName};
8use zvariant::{ObjectPath, OwnedObjectPath, OwnedValue, Value};
9
10use super::{Error, Result};
11use crate::{Connection, ObjectServer, interface, message::Header, object_server::SignalEmitter};
12
13/// The type returned by the [`ObjectManagerProxy::get_managed_objects`] method.
14pub type ManagedObjects =
15    HashMap<OwnedObjectPath, HashMap<OwnedInterfaceName, HashMap<String, OwnedValue>>>;
16
17/// Service-side [Object Manager][om] interface implementation.
18///
19/// The recommended path to add this interface at is the path form of the well-known name of a D-Bus
20/// service, or below. For example, if a D-Bus service is available at the well-known name
21/// `net.example.ExampleService1`, this interface should typically be registered at
22/// `/net/example/ExampleService1`, or below (to allow for multiple object managers in a service).
23///
24/// It is supported, but not recommended, to add this interface at the root path, `/`.
25///
26/// When added to an `ObjectServer`, the `InterfacesAdded` signal is emitted for all the objects
27/// under the `path` it's added at. You can use this fact to minimize the signal emissions by
28/// populating the entire (sub)tree under `path` before registering an object manager.
29///
30/// Because registering it reads the properties of every object under `path`, adding an
31/// `ObjectManager` at an ancestor of an interface from within that interface's own `&mut self`
32/// method will deadlock. See [`ObjectServer::at`](crate::ObjectServer::at) for details.
33///
34/// [om]: https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager
35#[derive(Debug, Clone)]
36pub struct ObjectManager;
37
38#[interface(
39    name = "org.freedesktop.DBus.ObjectManager",
40    introspection_docs = false,
41    proxy(visibility = "pub")
42)]
43impl ObjectManager {
44    /// The return value of this method is a dict whose keys are object paths. All returned object
45    /// paths are children of the object path implementing this interface, i.e. their object paths
46    /// start with the ObjectManager's object path plus '/'.
47    ///
48    /// Each value is a dict whose keys are interfaces names. Each value in this inner dict is the
49    /// same dict that would be returned by the org.freedesktop.DBus.Properties.GetAll() method for
50    /// that combination of object path and interface. If an interface has no properties, the empty
51    /// dict is returned.
52    async fn get_managed_objects(
53        &self,
54        #[zbus(object_server)] server: &ObjectServer,
55        #[zbus(connection)] connection: &Connection,
56        #[zbus(header)] header: Header<'_>,
57    ) -> Result<ManagedObjects> {
58        let path = header.path().ok_or(crate::Error::MissingField)?;
59        let root = server.root().read().await;
60        let node = root
61            .get_child(path)
62            .ok_or_else(|| Error::UnknownObject(format!("Unknown object '{path}'")))?;
63
64        node.get_managed_objects(server, connection).await
65    }
66
67    /// This signal is emitted when either a new object is added or when an existing object gains
68    /// one or more interfaces. The `interfaces_and_properties` argument contains a map with the
69    /// interfaces and properties (if any) that have been added to the given object path.
70    #[zbus(signal)]
71    pub async fn interfaces_added(
72        emitter: &SignalEmitter<'_>,
73        object_path: ObjectPath<'_>,
74        interfaces_and_properties: HashMap<InterfaceName<'_>, HashMap<&str, Value<'_>>>,
75    ) -> zbus::Result<()>;
76
77    /// This signal is emitted whenever an object is removed or it loses one or more interfaces.
78    /// The `interfaces` parameters contains a list of the interfaces that were removed.
79    #[zbus(signal)]
80    pub async fn interfaces_removed(
81        emitter: &SignalEmitter<'_>,
82        object_path: ObjectPath<'_>,
83        interfaces: Cow<'_, [InterfaceName<'_>]>,
84    ) -> zbus::Result<()>;
85}