dbus_crossroads/
context.rs1use std::marker::PhantomData;
2use dbus::arg::AppendAll;
3use dbus::channel::Sender;
4use std::sync::Arc;
5use crate::{MethodErr, utils::Dbg};
6
7#[derive(Debug)]
11pub struct Context {
12 path: dbus::Path<'static>,
13 interface: Option<dbus::strings::Interface<'static>>,
14 method: dbus::strings::Member<'static>,
15 message: dbus::Message,
16
17 has_error: bool,
18 reply: Option<dbus::Message>,
19 send_extra: Vec<dbus::Message>,
20 send_on_drop: Option<Dbg<Arc<dyn Sender + Send + Sync>>>,
21}
22
23impl Context {
24 pub fn new(msg: dbus::Message) -> Option<Self> {
28 if msg.msg_type() != dbus::MessageType::MethodCall { return None; }
29 let p = msg.path()?.into_static();
30 let i = msg.interface().map(|i| i.into_static());
31 let m = msg.member()?.into_static();
32 Some(Context {
33 path: p,
34 interface: i,
35 method: m,
36 message: msg,
37 reply: None,
38 send_on_drop: None,
39 send_extra: vec!(),
40 has_error: false,
41 })
42 }
43
44 pub fn check<R, F: FnOnce(&mut Context) -> Result<R, MethodErr>>(&mut self, f: F) -> Result<R, ()> {
46 f(self).map_err(|e| { self.reply_err(e); })
47 }
48
49 pub fn do_reply<F: FnOnce(&mut dbus::Message)>(&mut self, f: F) {
52 if self.message.get_no_reply() { return; }
53 if self.reply.is_some() { return; }
54 let mut msg = self.message.method_return();
55 f(&mut msg);
56 self.reply = Some(msg);
57 }
58
59 pub (crate) fn reply_ok<OA: AppendAll>(&mut self, oa: OA) -> PhantomData<OA> {
64 self.do_reply(|msg| { msg.append_all(oa); });
65 PhantomData
66 }
67
68 pub fn reply<OA: AppendAll>(&mut self, result: Result<OA, MethodErr>) -> PhantomData<OA> {
73 match result {
74 Ok(oa) => { self.reply_ok(oa); },
75 Err(e) => { self.reply_err(e); },
76 };
77 PhantomData
78 }
79
80 pub (crate) fn reply_err(&mut self, err: MethodErr) {
82 self.has_error = true;
83 if !self.message.get_no_reply() {
84 self.reply = Some(err.to_message(&self.message))
85 };
86 }
87
88 pub fn set_reply(&mut self, msg: Option<dbus::Message>, check_no_reply: bool, check_set: bool) {
92 if check_no_reply && self.message.get_no_reply() { return; }
93 if check_set && self.reply.is_some() { return; }
94 self.reply = msg;
95 }
96
97 pub fn flush_messages<S: dbus::channel::Sender + ?Sized>(&mut self, conn: &S) -> Result<(), ()> {
101 if let Some(msg) = self.reply.take() {
102 conn.send(msg)?;
103 }
104 for msg in self.send_extra.drain(..) {
105 conn.send(msg)?;
106 }
107 Ok(())
108 }
109
110 pub fn make_signal<'b, A, N>(&self, name: N, args: A) -> dbus::Message
112 where A: dbus::arg::AppendAll, N: Into<dbus::strings::Member<'b>> {
113 let mut msg = dbus::Message::signal(&self.path, self.interface.as_ref().unwrap(), &name.into());
114 msg.append_all(args);
115 msg
116 }
117
118 pub fn push_msg(&mut self, msg: dbus::Message) { self.send_extra.push(msg); }
120
121 pub fn path(&self) -> &dbus::Path<'static> { &self.path }
123
124 pub fn interface(&self) -> Option<&dbus::strings::Interface<'static>> { self.interface.as_ref() }
129
130 pub fn method(&self) -> &dbus::strings::Member<'static> { &self.method }
132
133 pub fn message(&self) -> &dbus::Message { &self.message }
135
136 pub fn has_reply(&self) -> bool { self.reply.is_some() }
138
139 pub fn has_error(&self) -> bool { self.has_error }
141
142 pub (crate) fn set_send_on_drop(&mut self, value: Arc<dyn Sender + Send + Sync>) {
143 self.send_on_drop = Some(Dbg(value));
144 }
145}
146
147impl Drop for Context {
148 fn drop(&mut self) {
149 if let Some(sender) = self.send_on_drop.take() {
150 let _ = self.flush_messages(&*sender.0);
151 }
152 }
153}