hooks.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. // Copyright 2019-2023 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. use crate::{
  5. api::ipc::{format_callback, format_callback_result, CallbackFn},
  6. app::App,
  7. Runtime, StateManager, Window,
  8. };
  9. use serde::{Deserialize, Serialize};
  10. use serde_json::Value as JsonValue;
  11. use serialize_to_javascript::{default_template, Template};
  12. use std::{future::Future, sync::Arc};
  13. #[cfg(feature = "tracing")]
  14. use tracing::Instrument;
  15. use tauri_macros::default_runtime;
  16. /// A closure that is run when the Tauri application is setting up.
  17. pub type SetupHook<R> =
  18. Box<dyn FnOnce(&mut App<R>) -> Result<(), Box<dyn std::error::Error>> + Send>;
  19. /// A closure that is run every time Tauri receives a message it doesn't explicitly handle.
  20. pub type InvokeHandler<R> = dyn Fn(Invoke<R>) + Send + Sync + 'static;
  21. /// A closure that is responsible for respond a JS message.
  22. pub type InvokeResponder<R> =
  23. dyn Fn(Window<R>, InvokeResponse, CallbackFn, CallbackFn) + Send + Sync + 'static;
  24. /// A closure that is run once every time a window is created and loaded.
  25. pub type OnPageLoad<R> = dyn Fn(Window<R>, PageLoadPayload) + Send + Sync + 'static;
  26. // todo: why is this derive broken but the output works manually?
  27. #[derive(Template)]
  28. #[default_template("../scripts/ipc.js")]
  29. pub(crate) struct IpcJavascript<'a> {
  30. pub(crate) isolation_origin: &'a str,
  31. }
  32. #[cfg(feature = "isolation")]
  33. #[derive(Template)]
  34. #[default_template("../scripts/isolation.js")]
  35. pub(crate) struct IsolationJavascript<'a> {
  36. pub(crate) isolation_src: &'a str,
  37. pub(crate) style: &'a str,
  38. }
  39. /// The payload for the [`OnPageLoad`] hook.
  40. #[derive(Debug, Clone, Deserialize)]
  41. pub struct PageLoadPayload {
  42. url: String,
  43. }
  44. impl PageLoadPayload {
  45. /// The page URL.
  46. pub fn url(&self) -> &str {
  47. &self.url
  48. }
  49. }
  50. /// The payload used on the IPC invoke.
  51. #[derive(Debug, Deserialize)]
  52. pub struct InvokePayload {
  53. /// The invoke command.
  54. pub cmd: String,
  55. #[serde(rename = "__tauriModule")]
  56. #[doc(hidden)]
  57. pub tauri_module: Option<String>,
  58. /// The success callback.
  59. pub callback: CallbackFn,
  60. /// The error callback.
  61. pub error: CallbackFn,
  62. /// The payload of the message.
  63. #[serde(flatten)]
  64. pub inner: JsonValue,
  65. }
  66. /// The message and resolver given to a custom command.
  67. #[default_runtime(crate::Wry, wry)]
  68. #[derive(Debug)]
  69. pub struct Invoke<R: Runtime> {
  70. /// The message passed.
  71. pub message: InvokeMessage<R>,
  72. /// The resolver of the message.
  73. pub resolver: InvokeResolver<R>,
  74. }
  75. /// Error response from an [`InvokeMessage`].
  76. #[derive(Debug)]
  77. pub struct InvokeError(JsonValue);
  78. impl InvokeError {
  79. /// Create an [`InvokeError`] as a string of the [`serde_json::Error`] message.
  80. #[inline(always)]
  81. pub fn from_serde_json(error: serde_json::Error) -> Self {
  82. Self(JsonValue::String(error.to_string()))
  83. }
  84. /// Create an [`InvokeError`] as a string of the [`anyhow::Error`] message.
  85. #[inline(always)]
  86. pub fn from_anyhow(error: anyhow::Error) -> Self {
  87. Self(JsonValue::String(format!("{error:#}")))
  88. }
  89. }
  90. impl<T: Serialize> From<T> for InvokeError {
  91. #[inline]
  92. fn from(value: T) -> Self {
  93. serde_json::to_value(value)
  94. .map(Self)
  95. .unwrap_or_else(Self::from_serde_json)
  96. }
  97. }
  98. impl From<crate::Error> for InvokeError {
  99. #[inline(always)]
  100. fn from(error: crate::Error) -> Self {
  101. Self(JsonValue::String(error.to_string()))
  102. }
  103. }
  104. /// Response from a [`InvokeMessage`] passed to the [`InvokeResolver`].
  105. #[derive(Debug)]
  106. pub enum InvokeResponse {
  107. /// Resolve the promise.
  108. Ok(JsonValue),
  109. /// Reject the promise.
  110. Err(InvokeError),
  111. }
  112. impl InvokeResponse {
  113. /// Turn a [`InvokeResponse`] back into a serializable result.
  114. #[inline(always)]
  115. pub fn into_result(self) -> Result<JsonValue, JsonValue> {
  116. match self {
  117. Self::Ok(v) => Ok(v),
  118. Self::Err(e) => Err(e.0),
  119. }
  120. }
  121. }
  122. impl<T: Serialize> From<Result<T, InvokeError>> for InvokeResponse {
  123. #[inline]
  124. fn from(result: Result<T, InvokeError>) -> Self {
  125. match result {
  126. Ok(ok) => match serde_json::to_value(ok) {
  127. Ok(value) => Self::Ok(value),
  128. Err(err) => Self::Err(InvokeError::from_serde_json(err)),
  129. },
  130. Err(err) => Self::Err(err),
  131. }
  132. }
  133. }
  134. impl From<InvokeError> for InvokeResponse {
  135. fn from(error: InvokeError) -> Self {
  136. Self::Err(error)
  137. }
  138. }
  139. /// Resolver of a invoke message.
  140. #[default_runtime(crate::Wry, wry)]
  141. #[derive(Debug)]
  142. pub struct InvokeResolver<R: Runtime> {
  143. window: Window<R>,
  144. pub(crate) callback: CallbackFn,
  145. pub(crate) error: CallbackFn,
  146. }
  147. impl<R: Runtime> InvokeResolver<R> {
  148. pub(crate) fn new(window: Window<R>, callback: CallbackFn, error: CallbackFn) -> Self {
  149. Self {
  150. window,
  151. callback,
  152. error,
  153. }
  154. }
  155. /// Reply to the invoke promise with an async task.
  156. pub fn respond_async<T, F>(self, task: F)
  157. where
  158. T: Serialize,
  159. F: Future<Output = Result<T, InvokeError>> + Send + 'static,
  160. {
  161. let task = async move {
  162. Self::return_task(self.window, task, self.callback, self.error).await;
  163. };
  164. #[cfg(feature = "tracing")]
  165. {
  166. let span = tracing::trace_span!("ipc::request::respond");
  167. crate::async_runtime::spawn(task.instrument(span));
  168. }
  169. #[cfg(not(feature = "tracing"))]
  170. crate::async_runtime::spawn(task);
  171. }
  172. /// Reply to the invoke promise with an async task which is already serialized.
  173. pub fn respond_async_serialized<F>(self, task: F)
  174. where
  175. F: Future<Output = Result<JsonValue, InvokeError>> + Send + 'static,
  176. {
  177. let task = async move {
  178. let response = match task.await {
  179. Ok(ok) => InvokeResponse::Ok(ok),
  180. Err(err) => InvokeResponse::Err(err),
  181. };
  182. Self::return_result(self.window, response, self.callback, self.error)
  183. };
  184. #[cfg(feature = "tracing")]
  185. {
  186. let span = tracing::trace_span!("ipc::request::respond");
  187. crate::async_runtime::spawn(task.instrument(span));
  188. }
  189. #[cfg(not(feature = "tracing"))]
  190. crate::async_runtime::spawn(task);
  191. }
  192. /// Reply to the invoke promise with a serializable value.
  193. pub fn respond<T: Serialize>(self, value: Result<T, InvokeError>) {
  194. #[cfg(feature = "tracing")]
  195. let _span = tracing::trace_span!("ipc::request::respond").entered();
  196. Self::return_result(self.window, value.into(), self.callback, self.error)
  197. }
  198. /// Resolve the invoke promise with a value.
  199. pub fn resolve<T: Serialize>(self, value: T) {
  200. #[cfg(feature = "tracing")]
  201. let _span = tracing::trace_span!("ipc::request::respond").entered();
  202. Self::return_result(self.window, Ok(value).into(), self.callback, self.error)
  203. }
  204. /// Reject the invoke promise with a value.
  205. pub fn reject<T: Serialize>(self, value: T) {
  206. #[cfg(feature = "tracing")]
  207. let _span = tracing::trace_span!("ipc::request::respond").entered();
  208. Self::return_result(
  209. self.window,
  210. Result::<(), _>::Err(value.into()).into(),
  211. self.callback,
  212. self.error,
  213. )
  214. }
  215. /// Reject the invoke promise with an [`InvokeError`].
  216. pub fn invoke_error(self, error: InvokeError) {
  217. #[cfg(feature = "tracing")]
  218. let _span = tracing::trace_span!("ipc::request::respond").entered();
  219. Self::return_result(self.window, error.into(), self.callback, self.error)
  220. }
  221. /// Asynchronously executes the given task
  222. /// and evaluates its Result to the JS promise described by the `success_callback` and `error_callback` function names.
  223. ///
  224. /// If the Result `is_ok()`, the callback will be the `success_callback` function name and the argument will be the Ok value.
  225. /// If the Result `is_err()`, the callback will be the `error_callback` function name and the argument will be the Err value.
  226. pub(crate) async fn return_task<T, F>(
  227. window: Window<R>,
  228. task: F,
  229. success_callback: CallbackFn,
  230. error_callback: CallbackFn,
  231. ) where
  232. T: Serialize,
  233. F: Future<Output = Result<T, InvokeError>> + Send + 'static,
  234. {
  235. let result = task.await;
  236. Self::return_closure(window, || result, success_callback, error_callback)
  237. }
  238. pub(crate) fn return_closure<T: Serialize, F: FnOnce() -> Result<T, InvokeError>>(
  239. window: Window<R>,
  240. f: F,
  241. success_callback: CallbackFn,
  242. error_callback: CallbackFn,
  243. ) {
  244. Self::return_result(window, f().into(), success_callback, error_callback)
  245. }
  246. pub(crate) fn return_result(
  247. window: Window<R>,
  248. response: InvokeResponse,
  249. success_callback: CallbackFn,
  250. error_callback: CallbackFn,
  251. ) {
  252. #[cfg(feature = "tracing")]
  253. let _span =
  254. tracing::trace_span!("ipc::request::response", response = format!("{response:?}")).entered();
  255. (window.invoke_responder())(window, response, success_callback, error_callback);
  256. }
  257. }
  258. pub fn window_invoke_responder<R: Runtime>(
  259. window: Window<R>,
  260. response: InvokeResponse,
  261. success_callback: CallbackFn,
  262. error_callback: CallbackFn,
  263. ) {
  264. #[cfg(feature = "tracing")]
  265. let _span = tracing::trace_span!("ipc::request::eval_response").entered();
  266. let callback_string =
  267. match format_callback_result(response.into_result(), success_callback, error_callback) {
  268. Ok(callback_string) => callback_string,
  269. Err(e) => format_callback(error_callback, &e.to_string())
  270. .expect("unable to serialize response string to json"),
  271. };
  272. let _ = window.eval(&callback_string);
  273. }
  274. /// An invoke message.
  275. #[default_runtime(crate::Wry, wry)]
  276. #[derive(Debug)]
  277. pub struct InvokeMessage<R: Runtime> {
  278. /// The window that received the invoke message.
  279. pub(crate) window: Window<R>,
  280. /// Application managed state.
  281. pub(crate) state: Arc<StateManager>,
  282. /// The IPC command.
  283. pub(crate) command: String,
  284. /// The JSON argument passed on the invoke message.
  285. pub(crate) payload: JsonValue,
  286. }
  287. impl<R: Runtime> InvokeMessage<R> {
  288. /// Create an new [`InvokeMessage`] from a payload send to a window.
  289. pub(crate) fn new(
  290. window: Window<R>,
  291. state: Arc<StateManager>,
  292. command: String,
  293. payload: JsonValue,
  294. ) -> Self {
  295. Self {
  296. window,
  297. state,
  298. command,
  299. payload,
  300. }
  301. }
  302. /// The invoke command.
  303. #[inline(always)]
  304. pub fn command(&self) -> &str {
  305. &self.command
  306. }
  307. /// The window that received the invoke.
  308. #[inline(always)]
  309. pub fn window(&self) -> Window<R> {
  310. self.window.clone()
  311. }
  312. /// A reference to window that received the invoke.
  313. #[inline(always)]
  314. pub fn window_ref(&self) -> &Window<R> {
  315. &self.window
  316. }
  317. /// A reference to the payload the invoke received.
  318. #[inline(always)]
  319. pub fn payload(&self) -> &JsonValue {
  320. &self.payload
  321. }
  322. /// The state manager associated with the application
  323. #[inline(always)]
  324. pub fn state(&self) -> Arc<StateManager> {
  325. self.state.clone()
  326. }
  327. /// A reference to the state manager associated with application.
  328. #[inline(always)]
  329. pub fn state_ref(&self) -> &StateManager {
  330. &self.state
  331. }
  332. }