1 | use std::{ |
2 | any::{Any, TypeId}, |
3 | collections::HashMap, |
4 | fmt::{self, Write}, |
5 | future::Future, |
6 | pin::Pin, |
7 | sync::Arc, |
8 | }; |
9 | |
10 | use async_trait::async_trait; |
11 | use zbus::message::Flags; |
12 | use zbus_names::{InterfaceName, MemberName}; |
13 | use zvariant::{DynamicType, OwnedValue, Value}; |
14 | |
15 | use crate::{ |
16 | async_lock::RwLock, fdo, message::Message, object_server::SignalContext, Connection, |
17 | ObjectServer, Result, |
18 | }; |
19 | use tracing::trace; |
20 | |
21 | /// A helper type returned by [`Interface`] callbacks. |
22 | pub enum DispatchResult<'a> { |
23 | /// This interface does not support the given method |
24 | NotFound, |
25 | |
26 | /// Retry with [Interface::call_mut]. |
27 | /// |
28 | /// This is equivalent to NotFound if returned by call_mut. |
29 | RequiresMut, |
30 | |
31 | /// The method was found and will be completed by running this Future |
32 | Async(Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>), |
33 | } |
34 | |
35 | impl<'a> DispatchResult<'a> { |
36 | /// Helper for creating the Async variant |
37 | pub fn new_async<F, T, E>(conn: &'a Connection, msg: &'a Message, f: F) -> Self |
38 | where |
39 | F: Future<Output = ::std::result::Result<T, E>> + Send + 'a, |
40 | T: serde::Serialize + DynamicType + Send + Sync, |
41 | E: zbus::DBusError + Send, |
42 | { |
43 | DispatchResult::Async(Box::pin(async move { |
44 | let hdr: Header<'_> = msg.header(); |
45 | let ret: Result = f.await; |
46 | if !hdr.primary().flags().contains(Flags::NoReplyExpected) { |
47 | match ret { |
48 | Ok(r) => conn.reply(msg, &r).await, |
49 | Err(e) => conn.reply_dbus_error(&hdr, e).await, |
50 | } |
51 | .map(|_seq: ()| ()) |
52 | } else { |
53 | trace!("No reply expected for {:?} by the caller." , msg); |
54 | Ok(()) |
55 | } |
56 | })) |
57 | } |
58 | } |
59 | |
60 | /// The trait is used to dispatch messages to an interface instance. |
61 | /// |
62 | /// This trait should be treated as unstable API and compatibility may break in minor |
63 | /// version bumps. Because of this and other reasons, it is not recommended to manually implement |
64 | /// this trait. The [`crate::dbus_interface`] macro implements it for you. |
65 | /// |
66 | /// If you have an advanced use case where `dbus_interface` is inadequate, consider using |
67 | /// [`crate::MessageStream`] or [`crate::blocking::MessageIterator`] instead. |
68 | #[async_trait ] |
69 | pub trait Interface: Any + Send + Sync { |
70 | /// Return the name of the interface. Ex: "org.foo.MyInterface" |
71 | fn name() -> InterfaceName<'static> |
72 | where |
73 | Self: Sized; |
74 | |
75 | /// Whether each method call will be handled from a different spawned task. |
76 | /// |
77 | /// Note: When methods are called from separate tasks, they may not be run in the order in which |
78 | /// they were called. |
79 | fn spawn_tasks_for_methods(&self) -> bool { |
80 | true |
81 | } |
82 | |
83 | /// Get a property value. Returns `None` if the property doesn't exist. |
84 | async fn get(&self, property_name: &str) -> Option<fdo::Result<OwnedValue>>; |
85 | |
86 | /// Return all the properties. |
87 | async fn get_all(&self) -> fdo::Result<HashMap<String, OwnedValue>>; |
88 | |
89 | /// Set a property value. |
90 | /// |
91 | /// Return [`DispatchResult::NotFound`] if the property doesn't exist, or |
92 | /// [`DispatchResult::RequiresMut`] if `set_mut` should be used instead. The default |
93 | /// implementation just returns `RequiresMut`. |
94 | fn set<'call>( |
95 | &'call self, |
96 | property_name: &'call str, |
97 | value: &'call Value<'_>, |
98 | ctxt: &'call SignalContext<'_>, |
99 | ) -> DispatchResult<'call> { |
100 | let _ = (property_name, value, ctxt); |
101 | DispatchResult::RequiresMut |
102 | } |
103 | |
104 | /// Set a property value. |
105 | /// |
106 | /// Returns `None` if the property doesn't exist. |
107 | /// |
108 | /// This will only be invoked if `set` returned `RequiresMut`. |
109 | async fn set_mut( |
110 | &mut self, |
111 | property_name: &str, |
112 | value: &Value<'_>, |
113 | ctxt: &SignalContext<'_>, |
114 | ) -> Option<fdo::Result<()>>; |
115 | |
116 | /// Call a method. |
117 | /// |
118 | /// Return [`DispatchResult::NotFound`] if the method doesn't exist, or |
119 | /// [`DispatchResult::RequiresMut`] if `call_mut` should be used instead. |
120 | /// |
121 | /// It is valid, though inefficient, for this to always return `RequiresMut`. |
122 | fn call<'call>( |
123 | &'call self, |
124 | server: &'call ObjectServer, |
125 | connection: &'call Connection, |
126 | msg: &'call Message, |
127 | name: MemberName<'call>, |
128 | ) -> DispatchResult<'call>; |
129 | |
130 | /// Call a `&mut self` method. |
131 | /// |
132 | /// This will only be invoked if `call` returned `RequiresMut`. |
133 | fn call_mut<'call>( |
134 | &'call mut self, |
135 | server: &'call ObjectServer, |
136 | connection: &'call Connection, |
137 | msg: &'call Message, |
138 | name: MemberName<'call>, |
139 | ) -> DispatchResult<'call>; |
140 | |
141 | /// Write introspection XML to the writer, with the given indentation level. |
142 | fn introspect_to_writer(&self, writer: &mut dyn Write, level: usize); |
143 | } |
144 | |
145 | /// A type for a reference counted Interface trait-object, with associated run-time details and a |
146 | /// manual Debug impl. |
147 | #[derive (Clone)] |
148 | pub(crate) struct ArcInterface { |
149 | pub instance: Arc<RwLock<dyn Interface>>, |
150 | pub spawn_tasks_for_methods: bool, |
151 | } |
152 | |
153 | impl ArcInterface { |
154 | pub fn new<I>(iface: I) -> Self |
155 | where |
156 | I: Interface, |
157 | { |
158 | let spawn_tasks_for_methods: bool = iface.spawn_tasks_for_methods(); |
159 | Self { |
160 | instance: Arc::new(data:RwLock::new(iface)), |
161 | spawn_tasks_for_methods, |
162 | } |
163 | } |
164 | } |
165 | |
166 | impl fmt::Debug for ArcInterface { |
167 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
168 | fDebugStruct<'_, '_>.debug_struct(name:"Arc<RwLock<dyn Interface>>" ) |
169 | .finish_non_exhaustive() |
170 | } |
171 | } |
172 | |
173 | // Note: while it is possible to implement this without `unsafe`, it currently requires a helper |
174 | // trait with a blanket impl that creates `dyn Any` refs. It's simpler (and more performant) to |
175 | // just check the type ID and do the downcast ourself. |
176 | // |
177 | // See https://github.com/rust-lang/rust/issues/65991 for a rustc feature that will make it |
178 | // possible to get a `dyn Any` ref directly from a `dyn Interface` ref; once that is stable, we can |
179 | // remove this unsafe code. |
180 | impl dyn Interface { |
181 | /// Return Any of self |
182 | pub(crate) fn downcast_ref<T: Any>(&self) -> Option<&T> { |
183 | if <dyn Interface as Any>::type_id(self) == TypeId::of::<T>() { |
184 | // SAFETY: If type ID matches, it means object is of type T |
185 | Some(unsafe { &*(self as *const dyn Interface as *const T) }) |
186 | } else { |
187 | None |
188 | } |
189 | } |
190 | |
191 | /// Return Any of self |
192 | pub(crate) fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> { |
193 | if <dyn Interface as Any>::type_id(self) == TypeId::of::<T>() { |
194 | // SAFETY: If type ID matches, it means object is of type T |
195 | Some(unsafe { &mut *(self as *mut dyn Interface as *mut T) }) |
196 | } else { |
197 | None |
198 | } |
199 | } |
200 | } |
201 | |