hooks.rs 9.4 KB

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