summaryrefslogtreecommitdiffstats
path: root/third_party/rust/dbus/src/dispatcher.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/dbus/src/dispatcher.rs')
-rw-r--r--third_party/rust/dbus/src/dispatcher.rs129
1 files changed, 129 insertions, 0 deletions
diff --git a/third_party/rust/dbus/src/dispatcher.rs b/third_party/rust/dbus/src/dispatcher.rs
new file mode 100644
index 0000000000..eda78ed586
--- /dev/null
+++ b/third_party/rust/dbus/src/dispatcher.rs
@@ -0,0 +1,129 @@
+use crate::{Message, MessageType, Error, to_c_str, c_str_to_slice};
+use std::ptr;
+
+use std::collections::HashMap;
+
+/// [Unstable and Experimental]
+pub trait MessageDispatcherConfig: Sized {
+ /// The type of method reply stored inside the dispatcher
+ type Reply;
+
+ /// Called when a method call has received a reply.
+ fn on_reply(reply: Self::Reply, msg: Message, dispatcher: &mut MessageDispatcher<Self>);
+
+ /// Called when a signal is received.
+ ///
+ /// Defaults to doing nothing.
+ #[allow(unused_variables)]
+ fn on_signal(msg: Message, dispatcher: &mut MessageDispatcher<Self>) {}
+
+ /// Called when a method call is received.
+ ///
+ /// Defaults to calling default_dispatch.
+ fn on_method_call(msg: Message, dispatcher: &mut MessageDispatcher<Self>) {
+ if let Some(reply) = MessageDispatcher::<Self>::default_dispatch(&msg) {
+ Self::on_send(reply, dispatcher);
+ }
+ }
+
+ /// Called in the other direction, i e, when a message should be sent over the connection.
+ fn on_send(msg: Message, dispatcher: &mut MessageDispatcher<Self>);
+}
+
+/// Dummy implementation
+impl MessageDispatcherConfig for () {
+ type Reply = ();
+ fn on_reply(_: Self::Reply, _: Message, _: &mut MessageDispatcher<Self>) { unreachable!() }
+ fn on_send(_: Message, _: &mut MessageDispatcher<Self>) { unreachable!() }
+}
+
+/// [Unstable and Experimental] Meant for usage with RxTx.
+pub struct MessageDispatcher<C: MessageDispatcherConfig> {
+ waiting_replies: HashMap<u32, C::Reply>,
+ inner: C,
+}
+
+impl<C: MessageDispatcherConfig> MessageDispatcher<C> {
+
+ /// Creates a new message dispatcher.
+ pub fn new(inner: C) -> Self { MessageDispatcher {
+ waiting_replies: HashMap::new(),
+ inner: inner,
+ } }
+
+ /// "Inner" accessor
+ pub fn inner(&self) -> &C { &self.inner }
+
+ /// "Inner" mutable accessor
+ pub fn inner_mut(&mut self) -> &mut C { &mut self.inner }
+
+ /// Adds a waiting reply to a method call. func will be called when a method reply is dispatched.
+ pub fn add_reply(&mut self, serial: u32, func: C::Reply) {
+ if let Some(_) = self.waiting_replies.insert(serial, func) {
+ // panic because we're overwriting something else, or just ignore?
+ }
+ }
+
+ /// Cancels a waiting reply.
+ pub fn cancel_reply(&mut self, serial: u32) -> Option<C::Reply> {
+ self.waiting_replies.remove(&serial)
+ }
+
+
+ /// Dispatch an incoming message.
+ pub fn dispatch(&mut self, msg: Message) {
+ if let Some(serial) = msg.get_reply_serial() {
+ if let Some(sender) = self.waiting_replies.remove(&serial) {
+ C::on_reply(sender, msg, self);
+ return;
+ }
+ }
+ match msg.msg_type() {
+ MessageType::Signal => C::on_signal(msg, self),
+ MessageType::MethodCall => C::on_method_call(msg, self),
+ MessageType::Error | MessageType::MethodReturn => {},
+ MessageType::Invalid => unreachable!(),
+ }
+ }
+
+ /// Handles what we need to be a good D-Bus citizen.
+ ///
+ /// Call this if you have not handled the message yourself:
+ /// * It handles calls to org.freedesktop.DBus.Peer.
+ /// * For other method calls, it sends an error reply back that the method was unknown.
+ pub fn default_dispatch(m: &Message) -> Option<Message> {
+ Self::peer(&m)
+ .or_else(|| Self::unknown_method(&m))
+ }
+
+ /// Replies if this is a call to org.freedesktop.DBus.Peer, otherwise returns None.
+ pub fn peer(m: &Message) -> Option<Message> {
+ if let Some(intf) = m.interface() {
+ if &*intf != "org.freedesktop.DBus.Peer" { return None; }
+ if let Some(method) = m.member() {
+ if &*method == "Ping" { return Some(m.method_return()) }
+ if &*method == "GetMachineId" {
+ let mut r = m.method_return();
+ let mut e = Error::empty();
+ unsafe {
+ let id = ffi::dbus_try_get_local_machine_id(e.get_mut());
+ if id != ptr::null_mut() {
+ r = r.append1(c_str_to_slice(&(id as *const _)).unwrap());
+ ffi::dbus_free(id as *mut _);
+ return Some(r)
+ }
+ }
+ }
+ }
+ Some(m.error(&"org.freedesktop.DBus.Error.UnknownMethod".into(), &to_c_str("Method does not exist")))
+ } else { None }
+ }
+
+ /// For method calls, it replies that the method was unknown, otherwise returns None.
+ pub fn unknown_method(m: &Message) -> Option<Message> {
+ if m.msg_type() != MessageType::MethodCall { return None; }
+ // if m.get_no_reply() { return None; } // The reference implementation does not do this?
+ Some(m.error(&"org.freedesktop.DBus.Error.UnknownMethod".into(), &to_c_str("Path, Interface, or Method does not exist")))
+ }
+}
+