1use crate::{
11 ipc::{InvokeBody, InvokeError, InvokeMessage},
12 Runtime,
13};
14use serde::{
15 de::{Error, Visitor},
16 Deserialize, Deserializer,
17};
18
19use tauri_utils::acl::resolved::ResolvedCommand;
20
21pub struct CommandItem<'a, R: Runtime> {
23 pub plugin: Option<&'static str>,
25
26 pub name: &'static str,
28
29 pub key: &'static str,
31
32 pub message: &'a InvokeMessage<R>,
34
35 pub acl: &'a Option<Vec<ResolvedCommand>>,
37}
38
39pub trait CommandArg<'de, R: Runtime>: Sized {
55 fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError>;
59}
60
61impl<'de, D: Deserialize<'de>, R: Runtime> CommandArg<'de, R> for D {
63 fn from_command(command: CommandItem<'de, R>) -> Result<D, InvokeError> {
64 let name = command.name;
65 let arg = command.key;
66 #[cfg(feature = "tracing")]
67 let _span = tracing::trace_span!("ipc::request::deserialize_arg", arg = arg).entered();
68 Self::deserialize(command).map_err(|e| crate::Error::InvalidArgs(name, arg, e).into())
69 }
70}
71
72macro_rules! pass {
76 ($fn:ident, $($arg:ident: $argt:ty),+) => {
77 fn $fn<V: Visitor<'de>>(self, $($arg: $argt),*) -> Result<V::Value, Self::Error> {
78 if self.key.is_empty() {
79 return Err(serde_json::Error::custom(format!(
80 "command {} has an argument with no name with a non-optional value",
81 self.name
82 )))
83 }
84
85 match &self.message.payload {
86 InvokeBody::Raw(_body) => {
87 Err(serde_json::Error::custom(format!(
88 "command {} expected a value for key {} but the IPC call used a bytes payload",
89 self.name, self.key
90 )))
91 }
92 InvokeBody::Json(v) => {
93 match v.get(self.key) {
94 Some(value) => value.$fn($($arg),*),
95 None => {
96 Err(serde_json::Error::custom(format!(
97 "command {} missing required key {}",
98 self.name, self.key
99 )))
100 }
101 }
102 }
103 }
104 }
105 }
106}
107
108impl<'de, R: Runtime> Deserializer<'de> for CommandItem<'de, R> {
114 type Error = serde_json::Error;
115
116 pass!(deserialize_any, visitor: V);
117 pass!(deserialize_bool, visitor: V);
118 pass!(deserialize_i8, visitor: V);
119 pass!(deserialize_i16, visitor: V);
120 pass!(deserialize_i32, visitor: V);
121 pass!(deserialize_i64, visitor: V);
122 pass!(deserialize_u8, visitor: V);
123 pass!(deserialize_u16, visitor: V);
124 pass!(deserialize_u32, visitor: V);
125 pass!(deserialize_u64, visitor: V);
126 pass!(deserialize_f32, visitor: V);
127 pass!(deserialize_f64, visitor: V);
128 pass!(deserialize_char, visitor: V);
129 pass!(deserialize_str, visitor: V);
130 pass!(deserialize_string, visitor: V);
131 pass!(deserialize_bytes, visitor: V);
132 pass!(deserialize_byte_buf, visitor: V);
133
134 fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
135 match &self.message.payload {
136 InvokeBody::Raw(_body) => Err(serde_json::Error::custom(format!(
137 "command {} expected a value for key {} but the IPC call used a bytes payload",
138 self.name, self.key
139 ))),
140 InvokeBody::Json(v) => match v.get(self.key) {
141 Some(value) => value.deserialize_option(visitor),
142 None => visitor.visit_none(),
143 },
144 }
145 }
146
147 pass!(deserialize_unit, visitor: V);
148 pass!(deserialize_unit_struct, name: &'static str, visitor: V);
149 pass!(deserialize_newtype_struct, name: &'static str, visitor: V);
150 pass!(deserialize_seq, visitor: V);
151 pass!(deserialize_tuple, len: usize, visitor: V);
152
153 pass!(
154 deserialize_tuple_struct,
155 name: &'static str,
156 len: usize,
157 visitor: V
158 );
159
160 pass!(deserialize_map, visitor: V);
161
162 pass!(
163 deserialize_struct,
164 name: &'static str,
165 fields: &'static [&'static str],
166 visitor: V
167 );
168
169 pass!(
170 deserialize_enum,
171 name: &'static str,
172 fields: &'static [&'static str],
173 visitor: V
174 );
175
176 pass!(deserialize_identifier, visitor: V);
177 pass!(deserialize_ignored_any, visitor: V);
178}
179
180#[doc(hidden)]
184pub mod private {
185 use crate::{
186 ipc::{InvokeError, InvokeResolver, InvokeResponseBody, IpcResponse},
187 Runtime,
188 };
189 use futures_util::{FutureExt, TryFutureExt};
190 use std::future::Future;
191 #[cfg(feature = "tracing")]
192 pub use tracing;
193
194 pub struct ResponseTag;
197
198 pub trait ResponseKind {
199 #[inline(always)]
200 fn blocking_kind(&self) -> ResponseTag {
201 ResponseTag
202 }
203
204 #[inline(always)]
205 fn async_kind(&self) -> ResponseTag {
206 ResponseTag
207 }
208 }
209
210 impl<T: IpcResponse> ResponseKind for &T {}
211
212 impl ResponseTag {
213 #[inline(always)]
214 pub fn block<R, T>(self, value: T, resolver: InvokeResolver<R>)
215 where
216 R: Runtime,
217 T: IpcResponse,
218 {
219 resolver.respond(Ok(value))
220 }
221
222 #[inline(always)]
223 pub fn future<T>(
224 self,
225 value: T,
226 ) -> impl Future<Output = Result<InvokeResponseBody, InvokeError>>
227 where
228 T: IpcResponse,
229 {
230 std::future::ready(value.body().map_err(InvokeError::from_error))
231 }
232 }
233
234 pub struct ResultTag;
237
238 pub trait ResultKind {
239 #[inline(always)]
240 fn blocking_kind(&self) -> ResultTag {
241 ResultTag
242 }
243
244 #[inline(always)]
245 fn async_kind(&self) -> ResultTag {
246 ResultTag
247 }
248 }
249
250 impl<T: IpcResponse, E: Into<InvokeError>> ResultKind for Result<T, E> {}
251
252 impl ResultTag {
253 #[inline(always)]
254 pub fn block<R, T, E>(self, value: Result<T, E>, resolver: InvokeResolver<R>)
255 where
256 R: Runtime,
257 T: IpcResponse,
258 E: Into<InvokeError>,
259 {
260 resolver.respond(value.map_err(Into::into))
261 }
262
263 #[inline(always)]
264 pub fn future<T, E>(
265 self,
266 value: Result<T, E>,
267 ) -> impl Future<Output = Result<InvokeResponseBody, InvokeError>>
268 where
269 T: IpcResponse,
270 E: Into<InvokeError>,
271 {
272 std::future::ready(
273 value
274 .map_err(Into::into)
275 .and_then(|value| value.body().map_err(InvokeError::from_error)),
276 )
277 }
278 }
279
280 pub struct FutureTag;
283
284 pub trait FutureKind {
285 #[inline(always)]
286 fn async_kind(&self) -> FutureTag {
287 FutureTag
288 }
289 }
290 impl<T: IpcResponse, F: Future<Output = T>> FutureKind for &F {}
291
292 impl FutureTag {
293 #[inline(always)]
294 pub fn future<T, F>(
295 self,
296 value: F,
297 ) -> impl Future<Output = Result<InvokeResponseBody, InvokeError>>
298 where
299 T: IpcResponse,
300 F: Future<Output = T> + Send + 'static,
301 {
302 value.map(|value| value.body().map_err(InvokeError::from_error))
303 }
304 }
305
306 pub struct ResultFutureTag;
309
310 pub trait ResultFutureKind {
311 #[inline(always)]
312 fn async_kind(&self) -> ResultFutureTag {
313 ResultFutureTag
314 }
315 }
316
317 impl<T: IpcResponse, E: Into<InvokeError>, F: Future<Output = Result<T, E>>> ResultFutureKind
318 for F
319 {
320 }
321
322 impl ResultFutureTag {
323 #[inline(always)]
324 pub fn future<T, E, F>(
325 self,
326 value: F,
327 ) -> impl Future<Output = Result<InvokeResponseBody, InvokeError>>
328 where
329 T: IpcResponse,
330 E: Into<InvokeError>,
331 F: Future<Output = Result<T, E>> + Send,
332 {
333 value
334 .err_into()
335 .map(|result| result.and_then(|value| value.body().map_err(InvokeError::from_error)))
336 }
337 }
338}