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