diff options
Diffstat (limited to 'third_party/rust/dbus/src/prop.rs')
-rw-r--r-- | third_party/rust/dbus/src/prop.rs | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/third_party/rust/dbus/src/prop.rs b/third_party/rust/dbus/src/prop.rs new file mode 100644 index 0000000000..8c52872e1d --- /dev/null +++ b/third_party/rust/dbus/src/prop.rs @@ -0,0 +1,136 @@ +use super::{Connection, Message, MessageItem, Error, Path, Interface, BusName}; +use std::collections::BTreeMap; + +/// Client side properties - get and set properties on a remote application. +pub struct Props<'a> { + name: BusName<'a>, + path: Path<'a>, + interface: Interface<'a>, + timeout_ms: i32, + conn: &'a Connection, +} + +impl<'a> Props<'a> { + /// Create a new Props. + pub fn new<N, P, I>(conn: &'a Connection, name: N, path: P, interface: I, timeout_ms: i32) -> Props<'a> + where N: Into<BusName<'a>>, P: Into<Path<'a>>, I: Into<Interface<'a>> { + Props { + name: name.into(), + path: path.into(), + interface: interface.into(), + timeout_ms: timeout_ms, + conn: conn, + } + } + + /// Get a single property's value. + pub fn get(&self, propname: &str) -> Result<MessageItem, Error> { + let mut m = Message::method_call(&self.name, &self.path, + &"org.freedesktop.DBus.Properties".into(), &"Get".into()); + m.append_items(&[self.interface.to_string().into(), propname.to_string().into()]); + let mut r = try!(self.conn.send_with_reply_and_block(m, self.timeout_ms)); + let reply = try!(r.as_result()).get_items(); + if reply.len() == 1 { + if let &MessageItem::Variant(ref v) = &reply[0] { + return Ok((**v).clone()) + } + } + let f = format!("Invalid reply for property get {}: '{:?}'", propname, reply); + return Err(Error::new_custom("InvalidReply", &f)); + } + + /// Set a single property's value. + pub fn set(&self, propname: &str, value: MessageItem) -> Result<(), Error> { + let mut m = Message::method_call(&self.name, &self.path, + &"org.freedesktop.DBus.Properties".into(), &"Set".into()); + m.append_items(&[self.interface.to_string().into(), propname.to_string().into(), Box::new(value).into()]); + let mut r = try!(self.conn.send_with_reply_and_block(m, self.timeout_ms)); + try!(r.as_result()); + Ok(()) + } + + /// Get a map of all the properties' names and their values. + pub fn get_all(&self) -> Result<BTreeMap<String, MessageItem>, Error> { + let mut m = Message::method_call(&self.name, &self.path, + &"org.freedesktop.DBus.Properties".into(), &"GetAll".into()); + m.append_items(&[self.interface.to_string().into()]); + let mut r = try!(self.conn.send_with_reply_and_block(m, self.timeout_ms)); + let reply = try!(r.as_result()).get_items(); + + (|| { + if reply.len() != 1 { return Err(()) }; + let mut t = BTreeMap::new(); + let a: &[MessageItem] = try!(reply[0].inner()); + for p in a.iter() { + let (k, v) = try!(p.inner()); + let (k, v): (&String, &MessageItem) = (try!(k.inner()), try!(v.inner())); + t.insert(k.clone(), v.clone()); + } + Ok(t) + })().map_err(|_| { + let f = format!("Invalid reply for property GetAll: '{:?}'", reply); + Error::new_custom("InvalidReply", &f) + }) + } +} + +/// Wrapper around Props that keeps a map of fetched properties. +pub struct PropHandler<'a> { + p: Props<'a>, + map: BTreeMap<String, MessageItem>, +} + +impl<'a> PropHandler<'a> { + /// Create a new PropHandler from a Props. + pub fn new(p: Props) -> PropHandler { + PropHandler { p: p, map: BTreeMap::new() } + } + + /// Get a map of all the properties' names and their values. + pub fn get_all(&mut self) -> Result<(), Error> { + self.map = try!(self.p.get_all()); + Ok(()) + } + + /// Get a mutable reference to the PropHandler's fetched properties. + pub fn map_mut(&mut self) -> &mut BTreeMap<String, MessageItem> { &mut self.map } + + /// Get a reference to the PropHandler's fetched properties. + pub fn map(&self) -> &BTreeMap<String, MessageItem> { &self.map } + + /// Get a single property's value. + pub fn get(&mut self, propname: &str) -> Result<&MessageItem, Error> { + let v = try!(self.p.get(propname)); + self.map.insert(propname.to_string(), v); + Ok(self.map.get(propname).unwrap()) + } + + /// Set a single property's value. + pub fn set(&mut self, propname: &str, value: MessageItem) -> Result<(), Error> { + try!(self.p.set(propname, value.clone())); + self.map.insert(propname.to_string(), value); + Ok(()) + } +} + + +/* Unfortunately org.freedesktop.DBus has no properties we can use for testing, but PolicyKit should be around on most distros. */ +#[test] +fn test_get_policykit_version() { + use super::BusType; + let c = Connection::get_private(BusType::System).unwrap(); + let p = Props::new(&c, "org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority", + "org.freedesktop.PolicyKit1.Authority", 10000); + + /* Let's use both the get and getall methods and see if we get the same result */ + let v = p.get("BackendVersion").unwrap(); + let vall = p.get_all().unwrap(); + let v2 = vall.get("BackendVersion").unwrap(); + + assert_eq!(&v, &*v2); + match v { + MessageItem::Str(ref s) => { println!("Policykit Backend version is {}", s); } + _ => { panic!("Invalid Get: {:?}", v); } + }; +} + |