use super::utils::{ArcMap, Iter, IterE, Annotations, Introspect}; use super::{Factory, MethodType, MethodInfo, MethodResult, MethodErr, DataType, Property, Method, Signal, methodtype}; use std::sync::{Arc, Mutex}; use {Member, Message, Path, Signature, MessageType, Connection, ConnectionItem, Error, arg, MsgHandler, MsgHandlerType, MsgHandlerResult}; use Interface as IfaceName; use std::fmt; use std::ffi::CStr; use super::leaves::prop_append_dict; fn introspect_map (h: &ArcMap, indent: &str) -> String { h.iter().fold("".into(), |a, (k, v)| { let (name, params, contents) = (v.xml_name(), v.xml_params(), v.xml_contents()); format!("{}{}<{} name=\"{}\"{}{}>\n", a, indent, name, &*k, params, if contents.len() > 0 { format!(">\n{}{}, D: DataType> { name: Arc>, methods: ArcMap, Method>, signals: ArcMap, Signal>, properties: ArcMap>, anns: Annotations, data: D::Interface, } impl, D: DataType> Interface { /// Builder function that adds a method to the interface. pub fn add_m>>>(mut self, m: I) -> Self { let m = m.into(); self.methods.insert(m.get_name().clone(), m); self } /// Builder function that adds a signal to the interface. pub fn add_s>>>(mut self, s: I) -> Self { let m = s.into(); self.signals.insert(m.get_name().clone(), m); self } /// Builder function that adds a property to the interface. pub fn add_p>>>(mut self, p: I) -> Self { let m = p.into(); self.properties.insert(m.get_name().to_owned(), m); self } /// Builder function that adds an annotation to this interface. pub fn annotate, V: Into>(mut self, name: N, value: V) -> Self { self.anns.insert(name, value); self } /// Builder function that adds an annotation that this entity is deprecated. pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") } /// Get interface name pub fn get_name(&self) -> &IfaceName<'static> { &self.name } /// Get associated data pub fn get_data(&self) -> &D::Interface { &self.data } /// Iterates over methods implemented by this interface. pub fn iter_m<'a>(&'a self) -> Iter<'a, Method> { IterE::Member(self.methods.values()).into() } /// Iterates over signals implemented by this interface. pub fn iter_s<'a>(&'a self) -> Iter<'a, Signal> { IterE::Member(self.signals.values()).into() } /// Iterates over properties implemented by this interface. pub fn iter_p<'a>(&'a self) -> Iter<'a, Property> { IterE::String(self.properties.values()).into() } } impl, D: DataType> Introspect for Interface { fn xml_name(&self) -> &'static str { "interface" } fn xml_params(&self) -> String { String::new() } fn xml_contents(&self) -> String { format!("{}{}{}{}", introspect_map(&self.methods, " "), introspect_map(&self.properties, " "), introspect_map(&self.signals, " "), self.anns.introspect(" ")) } } pub fn new_interface, D: DataType>(t: IfaceName<'static>, d: D::Interface) -> Interface { Interface { name: Arc::new(t), methods: ArcMap::new(), signals: ArcMap::new(), properties: ArcMap::new(), anns: Annotations::new(), data: d } } #[derive(Debug)] /// Cache of built-in interfaces, in order to save memory when many object paths implement the same interface(s). pub struct IfaceCache, D: DataType>(Mutex, Interface>>); impl, D: DataType> IfaceCache where D::Interface: Default { pub fn get> + Clone, F>(&self, s: S, f: F) -> Arc> where F: FnOnce(Interface) -> Interface { let s2 = s.clone().into(); let mut m = self.0.lock().unwrap(); m.entry(s2).or_insert_with(|| { let i = new_interface(s.into(), Default::default()); Arc::new(f(i)) }).clone() } } impl, D: DataType> IfaceCache { pub fn get_factory> + Clone, F>(&self, s: S, f: F) -> Arc> where F: FnOnce() -> Interface { let s2 = s.clone().into(); let mut m = self.0.lock().unwrap(); m.entry(s2).or_insert_with(|| { Arc::new(f()) }).clone() } pub fn new() -> Arc { Arc::new(IfaceCache(Mutex::new(ArcMap::new()))) } } #[derive(Debug)] /// A D-Bus Object Path. pub struct ObjectPath, D: DataType> { name: Arc>, default_iface: Option>, ifaces: ArcMap>, Interface>, ifacecache: Arc>, data: D::ObjectPath, } impl, D: DataType> ObjectPath { /// Get property name pub fn get_name(&self) -> &Path<'static> { &self.name } /// Get associated data pub fn get_data(&self) -> &D::ObjectPath { &self.data } /// Iterates over interfaces implemented by this object path. pub fn iter<'a>(&'a self) -> Iter<'a, Interface> { IterE::Iface(self.ifaces.values()).into() } pub(super) fn introspect(&self, tree: &Tree) -> String { let ifacestr = introspect_map(&self.ifaces, " "); let olen = self.name.len()+1; let childstr = tree.children(self, true).iter().fold("".to_string(), |na, n| format!("{} \n", na, &n.name[olen..]) ); let nodestr = format!(r##" {}{}"##, self.name, ifacestr, childstr); nodestr } fn get_iface<'a>(&'a self, iface_name: &'a CStr) -> Result<&Arc>, MethodErr> { let j = try!(IfaceName::from_slice(iface_name.to_bytes_with_nul()).map_err(|e| MethodErr::invalid_arg(&e))); self.ifaces.get(&j).ok_or_else(|| MethodErr::no_interface(&j)) } fn prop_get(&self, m: &MethodInfo) -> MethodResult { let (iname, prop_name): (&CStr, &str) = try!(m.msg.read2()); let iface = try!(self.get_iface(iname)); let prop: &Property = try!(iface.properties.get(&String::from(prop_name)) .ok_or_else(|| MethodErr::no_property(&prop_name))); try!(prop.can_get()); let mut mret = m.msg.method_return(); { let mut iter = arg::IterAppend::new(&mut mret); let pinfo = m.to_prop_info(iface, prop); try!(prop.get_as_variant(&mut iter, &pinfo)); } Ok(vec!(mret)) } fn prop_get_all(&self, m: &MethodInfo) -> MethodResult { let iface = try!(self.get_iface(try!(m.msg.read1()))); let mut mret = m.msg.method_return(); try!(prop_append_dict(&mut arg::IterAppend::new(&mut mret), iface.properties.values().map(|v| &**v), m)); Ok(vec!(mret)) } fn prop_set(&self, m: &MethodInfo) -> MethodResult { let (iname, prop_name): (&CStr, &str) = try!(m.msg.read2()); let iface = try!(self.get_iface(iname)); let prop: &Property = try!(iface.properties.get(&String::from(prop_name)) .ok_or_else(|| MethodErr::no_property(&prop_name))); let mut iter = arg::Iter::new(m.msg); iter.next(); iter.next(); let mut iter2 = iter; try!(prop.can_set(Some(iter))); let pinfo = m.to_prop_info(iface, prop); let mut r: Vec = try!(prop.set_as_variant(&mut iter2, &pinfo)).into_iter().collect(); r.push(m.msg.method_return()); Ok(r) } fn get_managed_objects(&self, m: &MethodInfo) -> MethodResult { use arg::{Dict, Variant}; let mut paths = m.tree.children(&self, false); paths.push(&self); let mut result = Ok(()); let mut r = m.msg.method_return(); { let mut i = arg::IterAppend::new(&mut r); i.append_dict(&Signature::make::(), &Signature::make::,()>,()>>(), |ii| { for p in paths { ii.append_dict_entry(|pi| { pi.append(&*p.name); pi.append_dict(&Signature::make::<&str>(), &Signature::make::,()>>(), |pii| { for ifaces in p.ifaces.values() { let m2 = MethodInfo { msg: m.msg, path: p, iface: ifaces, tree: m.tree, method: m.method }; pii.append_dict_entry(|ppii| { ppii.append(&**ifaces.name); result = prop_append_dict(ppii, ifaces.properties.values().map(|v| &**v), &m2); }); if result.is_err() { break; } } }); }); if result.is_err() { break; } } }); } try!(result); Ok(vec!(r)) } fn handle(&self, m: &Message, t: &Tree) -> MethodResult { let iname = m.interface().or_else(|| { self.default_iface.clone() }); let i = try!(iname.and_then(|i| self.ifaces.get(&i)).ok_or_else(|| MethodErr::no_interface(&""))); let me = try!(m.member().and_then(|me| i.methods.get(&me)).ok_or_else(|| MethodErr::no_method(&""))); let minfo = MethodInfo { msg: m, tree: t, path: self, iface: i, method: me }; me.call(&minfo) } } impl, D: DataType> ObjectPath where ::Interface: Default, ::Method: Default { /// Adds introspection support for this object path. pub fn introspectable(self) -> Self { let z = self.ifacecache.get_factory("org.freedesktop.DBus.Introspectable", || { let f = Factory::from(self.ifacecache.clone()); methodtype::org_freedesktop_dbus_introspectable_server(&f, Default::default()) }); self.add(z) } /// Builder function that adds a interface to the object path. pub fn add>>>(mut self, s: I) -> Self { let m = s.into(); if !m.properties.is_empty() { self.add_property_handler(); } self.ifaces.insert(m.name.clone(), m); self } /// Builder function that sets what interface should be dispatched on an incoming /// method call without interface. pub fn default_interface(mut self, i: IfaceName<'static>) -> Self { self.default_iface = Some(i); self } /// Adds ObjectManager support for this object path. /// /// It is not possible to add/remove interfaces while the object path belongs to a tree, /// hence no InterfacesAdded / InterfacesRemoved signals are sent. pub fn object_manager(mut self) -> Self { use arg::{Variant, Dict}; let ifname = IfaceName::from("org.freedesktop.DBus.ObjectManager"); if self.ifaces.contains_key(&ifname) { return self }; let z = self.ifacecache.get(ifname, |i| { i.add_m(super::leaves::new_method("GetManagedObjects".into(), Default::default(), M::make_method(|m| m.path.get_managed_objects(m))) .outarg::,()>,()>,()>,_>("objpath_interfaces_and_properties")) }); self.ifaces.insert(z.name.clone(), z); self } fn add_property_handler(&mut self) { use arg::{Variant, Dict}; let ifname = IfaceName::from("org.freedesktop.DBus.Properties"); if self.ifaces.contains_key(&ifname) { return }; let z = self.ifacecache.get(ifname, |i| { i.add_m(super::leaves::new_method("Get".into(), Default::default(), M::make_method(|m| m.path.prop_get(m))) .inarg::<&str,_>("interface_name") .inarg::<&str,_>("property_name") .outarg::,_>("value")) .add_m(super::leaves::new_method("GetAll".into(), Default::default(), M::make_method(|m| m.path.prop_get_all(m))) .inarg::<&str,_>("interface_name") .outarg::, ()>,_>("props")) .add_m(super::leaves::new_method("Set".into(), Default::default(), M::make_method(|m| m.path.prop_set(m))) .inarg::<&str,_>("interface_name") .inarg::<&str,_>("property_name") .inarg::,_>("value")) }); self.ifaces.insert(z.name.clone(), z); } } pub fn new_objectpath, D: DataType>(n: Path<'static>, d: D::ObjectPath, cache: Arc>) -> ObjectPath { ObjectPath { name: Arc::new(n), data: d, ifaces: ArcMap::new(), ifacecache: cache, default_iface: None } } /// A collection of object paths. #[derive(Debug, Default)] pub struct Tree, D: DataType> { paths: ArcMap>, ObjectPath>, data: D::Tree, } impl, D: DataType> Tree { /// Builder function that adds an object path to this tree. /// /// Note: This does not register a path with the connection, so if the tree is currently registered, /// you might want to call Connection::register_object_path to add the path manually. pub fn add>>>(mut self, s: I) -> Self { self.insert(s); self } /// Get a reference to an object path from the tree. pub fn get(&self, p: &Path<'static>) -> Option<&Arc>> { self.paths.get(p) } /// Iterates over object paths in this tree. pub fn iter<'a>(&'a self) -> Iter<'a, ObjectPath> { IterE::Path(self.paths.values()).into() } /// Non-builder function that adds an object path to this tree. /// /// Note: This does not register a path with the connection, so if the tree is currently registered, /// you might want to call Connection::register_object_path to add the path manually. pub fn insert>>>(&mut self, s: I) { let m = s.into(); self.paths.insert(m.name.clone(), m); } /// Remove a object path from the Tree. Returns the object path removed, or None if not found. /// /// Note: This does not unregister a path with the connection, so if the tree is currently registered, /// you might want to call Connection::unregister_object_path to remove the path manually. pub fn remove(&mut self, p: &Path<'static>) -> Option>> { // There is no real reason p needs to have a static lifetime; but // the borrow checker doesn't agree. :-( self.paths.remove(p) } /// Registers or unregisters all object paths in the tree. pub fn set_registered(&self, c: &Connection, b: bool) -> Result<(), Error> { let mut regd_paths = Vec::new(); for p in self.paths.keys() { if b { match c.register_object_path(p) { Ok(()) => regd_paths.push(p.clone()), Err(e) => { while let Some(rp) = regd_paths.pop() { c.unregister_object_path(&rp); } return Err(e) } } } else { c.unregister_object_path(p); } } Ok(()) } /// This method takes an `ConnectionItem` iterator (you get it from `Connection::iter()`) /// and handles all matching items. Non-matching items (e g signals) are passed through. pub fn run<'a, I: Iterator>(&'a self, c: &'a Connection, i: I) -> TreeServer<'a, I, M, D> { TreeServer { iter: i, tree: &self, conn: c } } /// Handles a message. /// /// Will return None in case the object path was not /// found in this tree, or otherwise a list of messages to be sent back. pub fn handle(&self, m: &Message) -> Option> { if m.msg_type() != MessageType::MethodCall { None } else { m.path().and_then(|p| self.paths.get(&p).map(|s| s.handle(m, &self) .unwrap_or_else(|e| vec!(e.to_message(m))))) } } fn children(&self, o: &ObjectPath, direct_only: bool) -> Vec<&ObjectPath> { let parent: &str = &o.name; let plen = parent.len()+1; self.paths.values().filter_map(|v| { let k: &str = &v.name; if !k.starts_with(parent) || k.len() <= plen || &k[plen-1..plen] != "/" {None} else { let child = &k[plen..]; if direct_only && child.contains("/") {None} else {Some(&**v)} } }).collect() } /// Get associated data pub fn get_data(&self) -> &D::Tree { &self.data } } pub fn new_tree, D: DataType>(d: D::Tree) -> Tree { Tree { paths: ArcMap::new(), data: d } } impl, D: DataType> MsgHandler for Tree { fn handle_msg(&mut self, msg: &Message) -> Option { self.handle(msg).map(|v| MsgHandlerResult { handled: true, done: false, reply: v }) } fn handler_type(&self) -> MsgHandlerType { MsgHandlerType::MsgType(MessageType::MethodCall) } } impl, D: DataType> MsgHandler for Arc> { fn handle_msg(&mut self, msg: &Message) -> Option { self.handle(msg).map(|v| MsgHandlerResult { handled: true, done: false, reply: v }) } fn handler_type(&self) -> MsgHandlerType { MsgHandlerType::MsgType(MessageType::MethodCall) } } /// An iterator adapter that handles incoming method calls. /// /// Method calls that match an object path in the tree are handled and consumed by this /// iterator. Other messages are passed through. pub struct TreeServer<'a, I, M: MethodType + 'a, D: DataType + 'a> { iter: I, conn: &'a Connection, tree: &'a Tree, } impl<'a, I: Iterator, M: 'a + MethodType, D: DataType + 'a> Iterator for TreeServer<'a, I, M, D> { type Item = ConnectionItem; fn next(&mut self) -> Option { loop { let n = self.iter.next(); if let &Some(ConnectionItem::MethodCall(ref msg)) = &n { if let Some(v) = self.tree.handle(&msg) { // Probably the wisest is to ignore any send errors here - // maybe the remote has disconnected during our processing. for m in v { let _ = self.conn.send(m); }; continue; } } return n; } } } #[test] fn test_iter() { let f = super::Factory::new_fn::<()>(); let t = f.tree(()) .add(f.object_path("/echo", ()).introspectable() .add(f.interface("com.example.echo", ()) .add_m(f.method("Echo", (), |_| unimplemented!()).in_arg(("request", "s")).out_arg(("reply", "s"))) .add_p(f.property::("EchoCount", ())) .add_s(f.signal("Echoed", ()).arg(("data", "s")).deprecated() ) )).add(f.object_path("/echo/subpath", ())); let paths: Vec<_> = t.iter().collect(); assert_eq!(paths.len(), 2); } #[test] fn test_set_default_interface() { let iface_name: IfaceName<'_> = "com.example.echo".into(); let f = super::Factory::new_fn::<()>(); let t = f.object_path("/echo", ()).default_interface(iface_name.clone()); assert_eq!(t.default_iface, Some(iface_name)); } #[test] fn test_introspection() { let f = super::Factory::new_fn::<()>(); let t = f.object_path("/echo", ()).introspectable() .add(f.interface("com.example.echo", ()) .add_m(f.method("Echo", (), |_| unimplemented!()).in_arg(("request", "s")).out_arg(("reply", "s"))) .add_p(f.property::("EchoCount", ())) .add_s(f.signal("Echoed", ()).arg(("data", "s")).deprecated()) ); let actual_result = t.introspect(&f.tree(()).add(f.object_path("/echo/subpath", ()))); println!("\n=== Introspection XML start ===\n{}\n=== Introspection XML end ===", actual_result); let expected_result = r##" "##; assert_eq!(expected_result, actual_result); }