1 use crate::{Message, MessageType, Error, to_c_str, c_str_to_slice}; 2 use std::ptr; 3 4 use std::collections::HashMap; 5 6 /// [Unstable and Experimental] 7 pub trait MessageDispatcherConfig: Sized { 8 /// The type of method reply stored inside the dispatcher 9 type Reply; 10 11 /// Called when a method call has received a reply. on_reply(reply: Self::Reply, msg: Message, dispatcher: &mut MessageDispatcher<Self>)12 fn on_reply(reply: Self::Reply, msg: Message, dispatcher: &mut MessageDispatcher<Self>); 13 14 /// Called when a signal is received. 15 /// 16 /// Defaults to doing nothing. 17 #[allow(unused_variables)] on_signal(msg: Message, dispatcher: &mut MessageDispatcher<Self>)18 fn on_signal(msg: Message, dispatcher: &mut MessageDispatcher<Self>) {} 19 20 /// Called when a method call is received. 21 /// 22 /// Defaults to calling default_dispatch. on_method_call(msg: Message, dispatcher: &mut MessageDispatcher<Self>)23 fn on_method_call(msg: Message, dispatcher: &mut MessageDispatcher<Self>) { 24 if let Some(reply) = MessageDispatcher::<Self>::default_dispatch(&msg) { 25 Self::on_send(reply, dispatcher); 26 } 27 } 28 29 /// Called in the other direction, i e, when a message should be sent over the connection. on_send(msg: Message, dispatcher: &mut MessageDispatcher<Self>)30 fn on_send(msg: Message, dispatcher: &mut MessageDispatcher<Self>); 31 } 32 33 /// Dummy implementation 34 impl MessageDispatcherConfig for () { 35 type Reply = (); on_reply(_: Self::Reply, _: Message, _: &mut MessageDispatcher<Self>)36 fn on_reply(_: Self::Reply, _: Message, _: &mut MessageDispatcher<Self>) { unreachable!() } on_send(_: Message, _: &mut MessageDispatcher<Self>)37 fn on_send(_: Message, _: &mut MessageDispatcher<Self>) { unreachable!() } 38 } 39 40 /// [Unstable and Experimental] Meant for usage with RxTx. 41 pub struct MessageDispatcher<C: MessageDispatcherConfig> { 42 waiting_replies: HashMap<u32, C::Reply>, 43 inner: C, 44 } 45 46 impl<C: MessageDispatcherConfig> MessageDispatcher<C> { 47 48 /// Creates a new message dispatcher. new(inner: C) -> Self49 pub fn new(inner: C) -> Self { MessageDispatcher { 50 waiting_replies: HashMap::new(), 51 inner: inner, 52 } } 53 54 /// "Inner" accessor inner(&self) -> &C55 pub fn inner(&self) -> &C { &self.inner } 56 57 /// "Inner" mutable accessor inner_mut(&mut self) -> &mut C58 pub fn inner_mut(&mut self) -> &mut C { &mut self.inner } 59 60 /// Adds a waiting reply to a method call. func will be called when a method reply is dispatched. add_reply(&mut self, serial: u32, func: C::Reply)61 pub fn add_reply(&mut self, serial: u32, func: C::Reply) { 62 if let Some(_) = self.waiting_replies.insert(serial, func) { 63 // panic because we're overwriting something else, or just ignore? 64 } 65 } 66 67 /// Cancels a waiting reply. cancel_reply(&mut self, serial: u32) -> Option<C::Reply>68 pub fn cancel_reply(&mut self, serial: u32) -> Option<C::Reply> { 69 self.waiting_replies.remove(&serial) 70 } 71 72 73 /// Dispatch an incoming message. dispatch(&mut self, msg: Message)74 pub fn dispatch(&mut self, msg: Message) { 75 if let Some(serial) = msg.get_reply_serial() { 76 if let Some(sender) = self.waiting_replies.remove(&serial) { 77 C::on_reply(sender, msg, self); 78 return; 79 } 80 } 81 match msg.msg_type() { 82 MessageType::Signal => C::on_signal(msg, self), 83 MessageType::MethodCall => C::on_method_call(msg, self), 84 MessageType::Error | MessageType::MethodReturn => {}, 85 MessageType::Invalid => unreachable!(), 86 } 87 } 88 89 /// Handles what we need to be a good D-Bus citizen. 90 /// 91 /// Call this if you have not handled the message yourself: 92 /// * It handles calls to org.freedesktop.DBus.Peer. 93 /// * For other method calls, it sends an error reply back that the method was unknown. default_dispatch(m: &Message) -> Option<Message>94 pub fn default_dispatch(m: &Message) -> Option<Message> { 95 Self::peer(&m) 96 .or_else(|| Self::unknown_method(&m)) 97 } 98 99 /// Replies if this is a call to org.freedesktop.DBus.Peer, otherwise returns None. peer(m: &Message) -> Option<Message>100 pub fn peer(m: &Message) -> Option<Message> { 101 if let Some(intf) = m.interface() { 102 if &*intf != "org.freedesktop.DBus.Peer" { return None; } 103 if let Some(method) = m.member() { 104 if &*method == "Ping" { return Some(m.method_return()) } 105 if &*method == "GetMachineId" { 106 let mut r = m.method_return(); 107 let mut e = Error::empty(); 108 unsafe { 109 let id = ffi::dbus_try_get_local_machine_id(e.get_mut()); 110 if id != ptr::null_mut() { 111 r = r.append1(c_str_to_slice(&(id as *const _)).unwrap()); 112 ffi::dbus_free(id as *mut _); 113 return Some(r) 114 } 115 } 116 } 117 } 118 Some(m.error(&"org.freedesktop.DBus.Error.UnknownMethod".into(), &to_c_str("Method does not exist"))) 119 } else { None } 120 } 121 122 /// For method calls, it replies that the method was unknown, otherwise returns None. unknown_method(m: &Message) -> Option<Message>123 pub fn unknown_method(m: &Message) -> Option<Message> { 124 if m.msg_type() != MessageType::MethodCall { return None; } 125 // if m.get_no_reply() { return None; } // The reference implementation does not do this? 126 Some(m.error(&"org.freedesktop.DBus.Error.UnknownMethod".into(), &to_c_str("Path, Interface, or Method does not exist"))) 127 } 128 } 129 130