Source code

Revision control

Copy as Markdown

Other Tools

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); }
};
}