zbus/object_server/
node.rs

1//! The object server API.
2
3use std::{
4    collections::{hash_map::Entry, HashMap},
5    fmt::Write,
6};
7
8use zbus_names::InterfaceName;
9use zvariant::{ObjectPath, OwnedObjectPath, OwnedValue};
10
11use crate::{
12    fdo::{self, Introspectable, ManagedObjects, ObjectManager, Peer, Properties},
13    object_server::SignalEmitter,
14    Connection, ObjectServer,
15};
16
17use super::{ArcInterface, Interface};
18
19#[derive(Default, Debug)]
20pub(crate) struct Node {
21    path: OwnedObjectPath,
22    children: HashMap<String, Node>,
23    interfaces: HashMap<InterfaceName<'static>, ArcInterface>,
24}
25
26impl Node {
27    pub(crate) fn new(path: OwnedObjectPath) -> Self {
28        let mut node = Self {
29            path,
30            ..Default::default()
31        };
32        assert!(node.add_interface(Peer));
33        assert!(node.add_interface(Introspectable));
34        assert!(node.add_interface(Properties));
35
36        node
37    }
38
39    // Get the child Node at path.
40    pub(crate) fn get_child(&self, path: &ObjectPath<'_>) -> Option<&Node> {
41        let mut node = self;
42
43        for i in path.split('/').skip(1) {
44            if i.is_empty() {
45                continue;
46            }
47            match node.children.get(i) {
48                Some(n) => node = n,
49                None => return None,
50            }
51        }
52
53        Some(node)
54    }
55
56    /// Get the child Node at path. Optionally create one if it doesn't exist.
57    ///
58    /// This also returns the path of the parent node that implements ObjectManager (if any). If
59    /// multiple parents implement it (they shouldn't), then the closest one is returned.
60    pub(super) fn get_child_mut(
61        &mut self,
62        path: &ObjectPath<'_>,
63        create: bool,
64    ) -> (Option<&mut Node>, Option<ObjectPath<'_>>) {
65        let mut node = self;
66        let mut node_path = String::new();
67        let mut obj_manager_path = None;
68
69        for i in path.split('/').skip(1) {
70            if i.is_empty() {
71                continue;
72            }
73
74            if node.interfaces.contains_key(&ObjectManager::name()) {
75                obj_manager_path = Some((*node.path).clone());
76            }
77
78            write!(&mut node_path, "/{i}").unwrap();
79            match node.children.entry(i.into()) {
80                Entry::Vacant(e) => {
81                    if create {
82                        let path = node_path.as_str().try_into().expect("Invalid Object Path");
83                        node = e.insert(Node::new(path));
84                    } else {
85                        return (None, obj_manager_path);
86                    }
87                }
88                Entry::Occupied(e) => node = e.into_mut(),
89            }
90        }
91
92        (Some(node), obj_manager_path)
93    }
94
95    pub(crate) fn interface_lock(&self, interface_name: InterfaceName<'_>) -> Option<ArcInterface> {
96        self.interfaces.get(&interface_name).cloned()
97    }
98
99    pub(super) fn remove_interface(&mut self, interface_name: InterfaceName<'static>) -> bool {
100        self.interfaces.remove(&interface_name).is_some()
101    }
102
103    pub(super) fn is_empty(&self) -> bool {
104        !self.interfaces.keys().any(|k| {
105            *k != Peer::name()
106                && *k != Introspectable::name()
107                && *k != Properties::name()
108                && *k != ObjectManager::name()
109        })
110    }
111
112    pub(super) fn remove_node(&mut self, node: &str) -> bool {
113        self.children.remove(node).is_some()
114    }
115
116    pub(super) fn add_arc_interface(
117        &mut self,
118        name: InterfaceName<'static>,
119        arc_iface: ArcInterface,
120    ) -> bool {
121        match self.interfaces.entry(name) {
122            Entry::Vacant(e) => {
123                e.insert(arc_iface);
124                true
125            }
126            Entry::Occupied(_) => false,
127        }
128    }
129
130    fn add_interface<I>(&mut self, iface: I) -> bool
131    where
132        I: Interface,
133    {
134        self.add_arc_interface(I::name(), ArcInterface::new(iface))
135    }
136
137    async fn introspect_to_writer<W: Write + Send>(&self, writer: &mut W) {
138        enum Fragment<'a> {
139            /// Represent an unclosed node tree, could be further splitted into sub-`Fragment`s.
140            Node {
141                name: &'a str,
142                node: &'a Node,
143                level: usize,
144            },
145            /// Represent a closing `</node>`.
146            End { level: usize },
147        }
148
149        let mut stack = Vec::new();
150        stack.push(Fragment::Node {
151            name: "",
152            node: self,
153            level: 0,
154        });
155
156        // This can be seen as traversing the fragment tree in pre-order DFS with formatted XML
157        // fragment, splitted `Fragment::Node`s and `Fragment::End` being current node, left
158        // subtree and right leaf respectively.
159        while let Some(fragment) = stack.pop() {
160            match fragment {
161                Fragment::Node { name, node, level } => {
162                    stack.push(Fragment::End { level });
163
164                    for (name, node) in &node.children {
165                        stack.push(Fragment::Node {
166                            name,
167                            node,
168                            level: level + 2,
169                        })
170                    }
171
172                    if level == 0 {
173                        writeln!(
174                            writer,
175                            r#"
176<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
177 "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
178<node>"#
179                        )
180                        .unwrap();
181                    } else {
182                        writeln!(
183                            writer,
184                            "{:indent$}<node name=\"{}\">",
185                            "",
186                            name,
187                            indent = level
188                        )
189                        .unwrap();
190                    }
191
192                    for iface in node.interfaces.values() {
193                        iface
194                            .instance
195                            .read()
196                            .await
197                            .introspect_to_writer(writer, level + 2);
198                    }
199                }
200                Fragment::End { level } => {
201                    writeln!(writer, "{:indent$}</node>", "", indent = level).unwrap();
202                }
203            }
204        }
205    }
206
207    pub(crate) async fn introspect(&self) -> String {
208        let mut xml = String::with_capacity(1024);
209
210        self.introspect_to_writer(&mut xml).await;
211
212        xml
213    }
214
215    pub(crate) async fn get_managed_objects(
216        &self,
217        object_server: &ObjectServer,
218        connection: &Connection,
219    ) -> fdo::Result<ManagedObjects> {
220        let mut managed_objects = ManagedObjects::new();
221
222        // Recursively get all properties of all interfaces of descendants.
223        let mut node_list: Vec<_> = self.children.values().collect();
224        while let Some(node) = node_list.pop() {
225            let mut interfaces = HashMap::new();
226            for iface_name in node.interfaces.keys().filter(|n| {
227                // Filter standard interfaces.
228                *n != &Peer::name()
229                    && *n != &Introspectable::name()
230                    && *n != &Properties::name()
231                    && *n != &ObjectManager::name()
232            }) {
233                let props = node
234                    .get_properties(object_server, connection, iface_name.clone())
235                    .await?;
236                interfaces.insert(iface_name.clone().into(), props);
237            }
238            managed_objects.insert(node.path.clone(), interfaces);
239            node_list.extend(node.children.values());
240        }
241
242        Ok(managed_objects)
243    }
244
245    pub(super) async fn get_properties(
246        &self,
247        object_server: &ObjectServer,
248        connection: &Connection,
249        interface_name: InterfaceName<'_>,
250    ) -> fdo::Result<HashMap<String, OwnedValue>> {
251        let emitter = SignalEmitter::new(connection, self.path.clone())?;
252        self.interface_lock(interface_name)
253            .expect("Interface was added but not found")
254            .instance
255            .read()
256            .await
257            .get_all(object_server, connection, None, &emitter)
258            .await
259    }
260}