zbus/object_server/
node.rs1use 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 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 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 Node {
138 name: &'a str,
139 node: &'a Node,
140 level: usize,
141 },
142 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 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 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 *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}