diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/rust/dbus/examples/adv_server.rs | |
parent | Initial commit. (diff) | |
download | firefox-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.rs | 177 |
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); + } +} |