rpc.rs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. use serde::Serialize;
  2. use serde_json::Value as JsonValue;
  3. use std::fmt::Display;
  4. /// Formats a function name and argument to be evaluated as callback.
  5. ///
  6. /// # Examples
  7. /// ```
  8. /// use tauri_api::rpc::format_callback;
  9. /// // callback with a string argument
  10. /// let cb = format_callback("callback-function-name", "the string response");
  11. /// assert!(cb.contains(r#"window["callback-function-name"]("the string response")"#));
  12. /// ```
  13. ///
  14. /// ```
  15. /// use tauri_api::rpc::format_callback;
  16. /// use serde::Serialize;
  17. /// // callback with JSON argument
  18. /// #[derive(Serialize)]
  19. /// struct MyResponse {
  20. /// value: String
  21. /// }
  22. /// let cb = format_callback("callback-function-name", serde_json::to_value(&MyResponse {
  23. /// value: "some value".to_string()
  24. /// }).expect("failed to serialize"));
  25. /// assert!(cb.contains(r#"window["callback-function-name"]({"value":"some value"})"#));
  26. /// ```
  27. pub fn format_callback<T: Into<JsonValue>, S: AsRef<str> + Display>(
  28. function_name: S,
  29. arg: T,
  30. ) -> String {
  31. format!(
  32. r#"
  33. if (window["{fn}"]) {{
  34. window["{fn}"]({arg})
  35. }} else {{
  36. console.warn("[TAURI] Couldn't find callback id {fn} in window. This happens when the app is reloaded while Rust is running an asynchronous operation.")
  37. }}
  38. "#,
  39. fn = function_name,
  40. arg = arg.into().to_string()
  41. )
  42. }
  43. /// Formats a Result type to its Promise response.
  44. /// Useful for Promises handling.
  45. /// If the Result `is_ok()`, the callback will be the `success_callback` function name and the argument will be the Ok value.
  46. /// If the Result `is_err()`, the callback will be the `error_callback` function name and the argument will be the Err value.
  47. ///
  48. /// * `result` the Result to check
  49. /// * `success_callback` the function name of the Ok callback. Usually the `resolve` of the JS Promise.
  50. /// * `error_callback` the function name of the Err callback. Usually the `reject` of the JS Promise.
  51. ///
  52. /// Note that the callback strings are automatically generated by the `promisified` helper.
  53. ///
  54. /// # Examples
  55. /// ```
  56. /// use tauri_api::rpc::format_callback_result;
  57. /// let res: Result<u8, &str> = Ok(5);
  58. /// let cb = format_callback_result(res, "success_cb".to_string(), "error_cb".to_string()).expect("failed to format");
  59. /// assert!(cb.contains(r#"window["success_cb"](5)"#));
  60. ///
  61. /// let res: Result<&str, &str> = Err("error message here");
  62. /// let cb = format_callback_result(res, "success_cb".to_string(), "error_cb".to_string()).expect("failed to format");
  63. /// assert!(cb.contains(r#"window["error_cb"]("error message here")"#));
  64. /// ```
  65. pub fn format_callback_result<T: Serialize, E: Serialize>(
  66. result: Result<T, E>,
  67. success_callback: String,
  68. error_callback: String,
  69. ) -> crate::Result<String> {
  70. let rpc = match result {
  71. Ok(res) => format_callback(success_callback, serde_json::to_value(res)?),
  72. Err(err) => format_callback(error_callback, serde_json::to_value(err)?),
  73. };
  74. Ok(rpc)
  75. }
  76. #[cfg(test)]
  77. mod test {
  78. use crate::rpc::*;
  79. use quickcheck_macros::quickcheck;
  80. // check abritrary strings in the format callback function
  81. #[quickcheck]
  82. fn qc_formating(f: String, a: String) -> bool {
  83. // can not accept empty strings
  84. if f != "" && a != "" {
  85. // call format callback
  86. let fc = format_callback(f.clone(), a.clone());
  87. fc.contains(&format!(
  88. r#"window["{}"]({})"#,
  89. f,
  90. serde_json::Value::String(a),
  91. ))
  92. } else {
  93. true
  94. }
  95. }
  96. // check arbitrary strings in format_callback_result
  97. #[quickcheck]
  98. fn qc_format_res(result: Result<String, String>, c: String, ec: String) -> bool {
  99. let resp = format_callback_result(result.clone(), c.clone(), ec.clone())
  100. .expect("failed to format callback result");
  101. let (function, value) = match result {
  102. Ok(v) => (c, v),
  103. Err(e) => (ec, e),
  104. };
  105. resp.contains(&format!(
  106. r#"window["{}"]({})"#,
  107. function,
  108. serde_json::Value::String(value),
  109. ))
  110. }
  111. }