summaryrefslogtreecommitdiffstats
path: root/third_party/rust/dbus/examples/adv_server.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/dbus/examples/adv_server.rs
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/dbus/examples/adv_server.rs')
-rw-r--r--third_party/rust/dbus/examples/adv_server.rs177
1 files changed, 177 insertions, 0 deletions
diff --git a/third_party/rust/dbus/examples/adv_server.rs b/third_party/rust/dbus/examples/adv_server.rs
new file mode 100644
index 0000000000..a71fc39a6a
--- /dev/null
+++ b/third_party/rust/dbus/examples/adv_server.rs
@@ -0,0 +1,177 @@
+// More advanced server example.
+
+// 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.
+
+extern crate 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};
+
+// Our storage device
+#[derive(Debug)]
+struct Device {
+ description: String,
+ path: Path<'static>,
+ index: i32,
+ online: Cell<bool>,
+ checking: Cell<bool>,
+}
+
+// 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)
+}
+
+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>> {
+ // Create our bogus devices
+ let devices: Vec<Arc<Device>> = (0..10).map(|i| Arc::new(Device::new_bogus(i))).collect();
+
+ // 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.
+ if let 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"));
+ }
+ }
+}
+
+fn main() {
+ if let Err(e) = run() {
+ println!("{}", e);
+ }
+}