Skip to main content

zbus/object_server/
node.rs

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