// This is supposed to look like a D-Bus service that allows the user to manipulate storage devices.
// Note: in the dbus-codegen/example directory, there is a version of this example where dbus-codegen // was used to create some boilerplate code - feel free to compare the two examples.
externcrate dbus;
use std::sync::Arc; use std::sync::mpsc; use std::cell::Cell; use std::thread;
use dbus::{Connection, BusType, tree, Path}; use dbus::tree::{Interface, Signal, MTFn, Access, MethodErr, EmitsChangedSignal};
// Every storage device has its own object path. // We therefore create a link from the object path to the Device. #[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 { // Creates a "test" device (not a real one, since this is an example). fn new_bogus(index: 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),
}
}
}
// Here's where we implement the code for our interface. fn create_iface(check_complete_s: mpsc::Sender<i32>) -> (Interface<MTFn<TData>, TData>, Arc<Signal<TData>>) { let f = tree::Factory::new_fn();
let check_complete = Arc::new(f.signal("CheckComplete", ()));
(f.interface("com.example.dbus.rs.device", ()) // The online property can be both set and get
.add_p(f.property::<bool,_>("online", ())
.access(Access::ReadWrite)
.on_get(|i, m| { let dev: &Arc<Device> = m.path.get_data();
i.append(dev.online.get());
Ok(())
})
.on_set(|i, m| { let dev: &Arc<Device> = m.path.get_data(); let b: bool = try!(i.read()); if b && dev.checking.get() { return Err(MethodErr::failed(&"Device currently under check, cannot bring online"))
}
dev.online.set(b);
Ok(())
})
) // The "checking" property is read only
.add_p(f.property::<bool,_>("checking", ())
.emits_changed(EmitsChangedSignal::False)
.on_get(|i, m| { let dev: &Arc<Device> = m.path.get_data();
i.append(dev.checking.get());
Ok(())
})
) // ...and so is the "description" property
.add_p(f.property::<&str,_>("description", ())
.emits_changed(EmitsChangedSignal::Const)
.on_get(|i, m| { let dev: &Arc<Device> = m.path.get_data();
i.append(&dev.description);
Ok(())
})
) // ...add a method for starting a device check...
.add_m(f.method("check", (), move |m| { let dev: &Arc<Device> = m.path.get_data(); if dev.checking.get() { return Err(MethodErr::failed(&"Device currently under check, cannot start another check"))
} if dev.online.get() { return Err(MethodErr::failed(&"Device is currently online, cannot start check"))
}
dev.checking.set(true);
// Start some lengthy processing in a separate thread... let devindex = dev.index; let ch = check_complete_s.clone();
thread::spawn(move || {
// Bogus check of device use std::time::Duration;
thread::sleep(Duration::from_secs(15));
// Tell main thread that we finished
ch.send(devindex).unwrap();
});
Ok(vec!(m.msg.method_return()))
})) // Indicate that we send a special signal once checking has completed.
.add_s(check_complete.clone())
, check_complete)
}
let f = tree::Factory::new_fn(); letmut tree = f.tree(()); for dev in devices {
tree = tree.add(f.object_path(dev.path.clone(), dev.clone())
.introspectable()
.add(iface.clone())
);
}
tree
}
// Create tree let (check_complete_s, check_complete_r) = mpsc::channel::<i32>(); let (iface, sig) = create_iface(check_complete_s); let tree = create_tree(&devices, &Arc::new(iface));
// Setup DBus connection let c = try!(Connection::get_private(BusType::Session)); try!(c.register_name("com.example.dbus.rs.advancedserverexample", 0)); try!(tree.set_registered(&c, true));
// ...and serve incoming requests.
c.add_handler(tree); loop { // Wait for incoming messages. This will block up to one second. // Discard the result - relevant messages have already been handled.
c.incoming(1000).next();
// Do all other things we need to do in our main loop. iflet Ok(idx) = check_complete_r.try_recv() { let dev = &devices[idx as usize];
dev.checking.set(false); try!(c.send(sig.msg(&dev.path, &"com.example.dbus.rs.device".into())).map_err(|_| "Sending DBus signal failed"));
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.