extern crate dbus;
mod com_example_dbus_rs {
#![allow(dead_code)]
use dbus as dbus;
use dbus::arg;
use dbus::tree;
pub trait Device {
type Err;
fn check(&self) -> Result<(), Self::Err>;
fn get_checking(&self) -> Result<bool, Self::Err>;
fn get_description(&self) -> Result<String, Self::Err>;
fn get_online(&self) -> Result<bool, Self::Err>;
fn set_online(&self, value: bool) -> Result<(), Self::Err>;
}
impl<'a, C: ::std::ops::Deref<Target=dbus::Connection>> Device for dbus::ConnPath<'a, C> {
type Err = dbus::Error;
fn check(&self) -> Result<(), Self::Err> {
let mut m = self.method_call_with_args(&"com.example.dbus.rs.device".into(), &"check".into(), |_| {
})?;
m.as_result()?;
Ok(())
}
fn get_checking(&self) -> Result<bool, Self::Err> {
<Self as dbus::stdintf::org_freedesktop_dbus::Properties>::get(&self, "com.example.dbus.rs.device", "checking")
}
fn get_description(&self) -> Result<String, Self::Err> {
<Self as dbus::stdintf::org_freedesktop_dbus::Properties>::get(&self, "com.example.dbus.rs.device", "description")
}
fn get_online(&self) -> Result<bool, Self::Err> {
<Self as dbus::stdintf::org_freedesktop_dbus::Properties>::get(&self, "com.example.dbus.rs.device", "online")
}
fn set_online(&self, value: bool) -> Result<(), Self::Err> {
<Self as dbus::stdintf::org_freedesktop_dbus::Properties>::set(&self, "com.example.dbus.rs.device", "online", value)
}
}
pub fn device_server<F, T, D>(factory: &tree::Factory<tree::MTFn<D>, D>, data: D::Interface, f: F) -> tree::Interface<tree::MTFn<D>, D>
where
D: tree::DataType,
D::Method: Default,
D::Property: Default,
D::Signal: Default,
T: Device<Err=tree::MethodErr>,
F: 'static + for <'z> Fn(& 'z tree::MethodInfo<tree::MTFn<D>, D>) -> & 'z T,
{
let i = factory.interface("com.example.dbus.rs.device", data);
let f = ::std::sync::Arc::new(f);
let fclone = f.clone();
let h = move |minfo: &tree::MethodInfo<tree::MTFn<D>, D>| {
let d = fclone(minfo);
d.check()?;
let rm = minfo.msg.method_return();
Ok(vec!(rm))
};
let m = factory.method("check", Default::default(), h);
let i = i.add_m(m);
let p = factory.property::<bool, _>("checking", Default::default());
let p = p.access(tree::Access::Read);
let fclone = f.clone();
let p = p.on_get(move |a, pinfo| {
let minfo = pinfo.to_method_info();
let d = fclone(&minfo);
a.append(d.get_checking()?);
Ok(())
});
let i = i.add_p(p);
let p = factory.property::<&str, _>("description", Default::default());
let p = p.access(tree::Access::Read);
let fclone = f.clone();
let p = p.on_get(move |a, pinfo| {
let minfo = pinfo.to_method_info();
let d = fclone(&minfo);
a.append(d.get_description()?);
Ok(())
});
let i = i.add_p(p);
let p = factory.property::<bool, _>("online", Default::default());
let p = p.access(tree::Access::ReadWrite);
let fclone = f.clone();
let p = p.on_get(move |a, pinfo| {
let minfo = pinfo.to_method_info();
let d = fclone(&minfo);
a.append(d.get_online()?);
Ok(())
});
let fclone = f.clone();
let p = p.on_set(move |iter, pinfo| {
let minfo = pinfo.to_method_info();
let d = fclone(&minfo);
d.set_online(iter.read()?)?;
Ok(())
});
let i = i.add_p(p);
let s = factory.signal("CheckComplete", Default::default());
let i = i.add_s(s);
i
}
#[derive(Debug, Default)]
pub struct DeviceCheckComplete {
}
impl dbus::SignalArgs for DeviceCheckComplete {
const NAME: &'static str = "CheckComplete";
const INTERFACE: &'static str = "com.example.dbus.rs.device";
fn append(&self, _: &mut arg::IterAppend) {
}
fn get(&mut self, _: &mut arg::Iter) -> Result<(), arg::TypeMismatchError> {
Ok(())
}
}
}
use dbus::{Connection, BusType, tree, Path};
use dbus::tree::{Interface, MTFn, MethodErr};
use std::sync::Arc;
use std::sync::mpsc;
use std::cell::Cell;
use std::thread;
#[derive(Debug)]
struct Device {
description: String,
path: Path<'static>,
index: i32,
online: Cell<bool>,
checking: Cell<bool>,
check_complete_sender: mpsc::Sender<i32>,
}
#[derive(Copy, Clone, Default, Debug)]
struct TData;
impl tree::DataType for TData {
type Tree = ();
type ObjectPath = Arc<Device>;
type Property = ();
type Interface = ();
type Method = ();
type Signal = ();
}
impl Device {
fn new_bogus(index: i32, s: mpsc::Sender<i32>) -> Device {
Device {
description: format!("This is device {}, which is {}.", index,
["totally awesome", "really fancy", "still going strong"][(index as usize) % 3]),
path: format!("/Device{}", index).into(),
index: index,
online: Cell::new(index % 2 == 0),
checking: Cell::new(false),
check_complete_sender: s,
}
}
}
impl com_example_dbus_rs::Device for Device {
type Err = tree::MethodErr;
fn check(&self) -> Result<(), Self::Err> {
if self.checking.get() {
return Err(MethodErr::failed(&"Device currently under check, cannot start another check"))
}
if self.online.get() {
return Err(MethodErr::failed(&"Device is currently online, cannot start check"))
}
self.checking.set(true);
let devindex = self.index;
let ch = self.check_complete_sender.clone();
thread::spawn(move || {
use std::time::Duration;
thread::sleep(Duration::from_secs(15));
ch.send(devindex).unwrap();
});
Ok(())
}
fn get_checking(&self) -> Result<bool, Self::Err> {
Ok(self.checking.get())
}
fn get_description(&self) -> Result<String, Self::Err> {
Ok(self.description.clone())
}
fn get_online(&self) -> Result<bool, Self::Err> {
Ok(self.online.get())
}
fn set_online(&self, value: bool) -> Result<(), Self::Err> {
if value && self.checking.get() {
Err(MethodErr::failed(&"Device currently under check, cannot bring online")) }
else {
self.online.set(value);
Ok(())
}
}
}
fn create_iface() -> Interface<MTFn<TData>, TData> {
let f = tree::Factory::new_fn();
com_example_dbus_rs::device_server(&f, (), |m| {
let a: &Arc<Device> = m.path.get_data();
let b: &Device = &a;
b
})
}
fn create_tree(devices: &[Arc<Device>], iface: &Arc<Interface<MTFn<TData>, TData>>)
-> tree::Tree<MTFn<TData>, TData> {
let f = tree::Factory::new_fn();
let mut tree = f.tree(());
for dev in devices {
tree = tree.add(f.object_path(dev.path.clone(), dev.clone())
.introspectable()
.add(iface.clone())
);
}
tree
}
fn run() -> Result<(), Box<std::error::Error>> {
let (check_complete_s, check_complete_r) = mpsc::channel::<i32>();
let devices: Vec<Arc<Device>> = (0..10).map(|i|
Arc::new(Device::new_bogus(i, check_complete_s.clone()))
).collect();
let iface = create_iface();
let tree = create_tree(&devices, &Arc::new(iface));
let c = Connection::get_private(BusType::Session)?;
c.register_name("com.example.dbus.rs.advancedserverexample", 0)?;
tree.set_registered(&c, true)?;
c.add_handler(tree);
loop {
c.incoming(1000).next();
if let Ok(idx) = check_complete_r.try_recv() {
let dev = &devices[idx as usize];
dev.checking.set(false);
let sig = com_example_dbus_rs::DeviceCheckComplete {};
use dbus::SignalArgs;
c.send(sig.to_emit_message(&dev.path))
.map_err(|_| "Sending DBus signal failed")?;
}
}
}
fn main() {
if let Err(e) = run() {
println!("{}", e);
}
}