refactor(core): remove responder from custom invoke systems (#11027)

* refactor(core): remove responder from custom invoke systems

the responder can be set directly in the WebviewWindow::on_message call

* fix tests
This commit is contained in:
Lucas Fernandes Nogueira 2024-09-16 12:20:50 -03:00 committed by GitHub
parent e7fd676c27
commit 551e0624a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 102 additions and 121 deletions

View File

@ -0,0 +1,5 @@
---
"tauri": patch:breaking
---
Remove the `responder` part of a custom invoke system now that the responder can be set directly in the `tauri::WebviewWindow::on_message` function.

View File

@ -5,8 +5,7 @@
use crate::{
image::Image,
ipc::{
channel::ChannelDataIpcQueue, CallbackFn, CommandArg, CommandItem, Invoke, InvokeError,
InvokeHandler, InvokeResponder, InvokeResponse,
channel::ChannelDataIpcQueue, CommandArg, CommandItem, Invoke, InvokeError, InvokeHandler,
},
manager::{webview::UriSchemeProtocol, AppManager, Asset},
plugin::{Plugin, PluginStore},
@ -1169,9 +1168,6 @@ pub struct Builder<R: Runtime> {
/// The JS message handler.
invoke_handler: Box<InvokeHandler<R>>,
/// The JS message responder.
invoke_responder: Option<Arc<InvokeResponder<R>>>,
/// The script that initializes the `window.__TAURI_INTERNALS__.postMessage` function.
pub(crate) invoke_initialization_script: String,
@ -1248,7 +1244,6 @@ impl<R: Runtime> Builder<R> {
runtime_any_thread: false,
setup: Box::new(|_| Ok(())),
invoke_handler: Box::new(|_| false),
invoke_responder: None,
invoke_initialization_script: InvokeInitializationScript {
process_ipc_message_fn: crate::manager::webview::PROCESS_IPC_MESSAGE_FN,
os_name: std::env::consts::OS,
@ -1312,8 +1307,6 @@ impl<R: Runtime> Builder<R> {
/// Defines a custom JS message system.
///
/// The `responder` is a function that will be called when a command has been executed and must send a response to the JS layer.
///
/// The `initialization_script` is a script that initializes `window.__TAURI_INTERNALS__.postMessage`.
/// That function must take the `(message: object, options: object)` arguments and send it to the backend.
///
@ -1331,13 +1324,9 @@ impl<R: Runtime> Builder<R> {
///
/// Note that the implementation details is up to your implementation.
#[must_use]
pub fn invoke_system<F>(mut self, initialization_script: String, responder: F) -> Self
where
F: Fn(&Webview<R>, &str, &InvokeResponse, CallbackFn, CallbackFn) + Send + Sync + 'static,
{
pub fn invoke_system(mut self, initialization_script: String) -> Self {
self.invoke_initialization_script =
initialization_script.replace("__INVOKE_KEY__", &format!("\"{}\"", self.invoke_key));
self.invoke_responder.replace(Arc::new(responder));
self
}
@ -1797,7 +1786,7 @@ tauri::Builder::default()
self.webview_event_listeners,
#[cfg(desktop)]
HashMap::new(),
(self.invoke_responder, self.invoke_initialization_script),
self.invoke_initialization_script,
self.invoke_key,
));

View File

@ -325,7 +325,6 @@ fn handle_ipc_message<R: Runtime>(request: Request<String>, manager: &AppManager
request,
Box::new(move |webview, cmd, response, callback, error| {
use crate::ipc::Channel;
use crate::sealed::ManagerBase;
#[cfg(feature = "tracing")]
let _respond_span = tracing::trace_span!(
@ -334,104 +333,101 @@ fn handle_ipc_message<R: Runtime>(request: Request<String>, manager: &AppManager
)
.entered();
// the channel data command is the only command that uses a custom protocol on Linux
if webview.manager().webview.invoke_responder.is_none() {
fn responder_eval<R: Runtime>(
webview: &crate::Webview<R>,
js: crate::Result<String>,
error: CallbackFn,
) {
let eval_js = match js {
Ok(js) => js,
Err(e) => crate::ipc::format_callback::format(error, &e.to_string())
.expect("unable to serialize response error string to json"),
};
let _ = webview.eval(&eval_js);
}
let can_use_channel_for_response = cmd
!= crate::ipc::channel::FETCH_CHANNEL_DATA_COMMAND
&& !options.custom_protocol_ipc_blocked;
#[cfg(feature = "tracing")]
let mime_type = match &response {
InvokeResponse::Ok(InvokeResponseBody::Json(_)) => mime::APPLICATION_JSON,
InvokeResponse::Ok(InvokeResponseBody::Raw(_)) => mime::APPLICATION_OCTET_STREAM,
InvokeResponse::Err(_) => mime::APPLICATION_JSON,
fn responder_eval<R: Runtime>(
webview: &crate::Webview<R>,
js: crate::Result<String>,
error: CallbackFn,
) {
let eval_js = match js {
Ok(js) => js,
Err(e) => crate::ipc::format_callback::format(error, &e.to_string())
.expect("unable to serialize response error string to json"),
};
#[cfg(feature = "tracing")]
let _response_span = match &response {
InvokeResponse::Ok(InvokeResponseBody::Json(v)) => tracing::trace_span!(
"ipc::request::response",
response = v,
mime_type = mime_type.essence_str()
)
.entered(),
InvokeResponse::Ok(InvokeResponseBody::Raw(v)) => tracing::trace_span!(
"ipc::request::response",
response = format!("{v:?}"),
mime_type = mime_type.essence_str()
)
.entered(),
InvokeResponse::Err(e) => tracing::trace_span!(
"ipc::request::response",
response = format!("{e:?}"),
mime_type = mime_type.essence_str()
)
.entered(),
};
let _ = webview.eval(&eval_js);
}
match response {
InvokeResponse::Ok(InvokeResponseBody::Json(v)) => {
if !(cfg!(target_os = "macos") || cfg!(target_os = "ios"))
&& (v.starts_with('{') || v.starts_with('['))
&& can_use_channel_for_response
{
let _ = Channel::from_callback_fn(webview, callback)
.send(InvokeResponseBody::Json(v));
} else {
responder_eval(
&webview,
crate::ipc::format_callback::format_result_raw(
Result::<_, String>::Ok(v),
callback,
error,
),
let can_use_channel_for_response = cmd
!= crate::ipc::channel::FETCH_CHANNEL_DATA_COMMAND
&& !options.custom_protocol_ipc_blocked;
#[cfg(feature = "tracing")]
let mime_type = match &response {
InvokeResponse::Ok(InvokeResponseBody::Json(_)) => mime::APPLICATION_JSON,
InvokeResponse::Ok(InvokeResponseBody::Raw(_)) => mime::APPLICATION_OCTET_STREAM,
InvokeResponse::Err(_) => mime::APPLICATION_JSON,
};
#[cfg(feature = "tracing")]
let _response_span = match &response {
InvokeResponse::Ok(InvokeResponseBody::Json(v)) => tracing::trace_span!(
"ipc::request::response",
response = v,
mime_type = mime_type.essence_str()
)
.entered(),
InvokeResponse::Ok(InvokeResponseBody::Raw(v)) => tracing::trace_span!(
"ipc::request::response",
response = format!("{v:?}"),
mime_type = mime_type.essence_str()
)
.entered(),
InvokeResponse::Err(e) => tracing::trace_span!(
"ipc::request::response",
response = format!("{e:?}"),
mime_type = mime_type.essence_str()
)
.entered(),
};
match response {
InvokeResponse::Ok(InvokeResponseBody::Json(v)) => {
if !(cfg!(target_os = "macos") || cfg!(target_os = "ios"))
&& (v.starts_with('{') || v.starts_with('['))
&& can_use_channel_for_response
{
let _ =
Channel::from_callback_fn(webview, callback).send(InvokeResponseBody::Json(v));
} else {
responder_eval(
&webview,
crate::ipc::format_callback::format_result_raw(
Result::<_, String>::Ok(v),
callback,
error,
)
}
}
InvokeResponse::Ok(InvokeResponseBody::Raw(v)) => {
if cfg!(target_os = "macos")
|| cfg!(target_os = "ios")
|| !can_use_channel_for_response
{
responder_eval(
&webview,
crate::ipc::format_callback::format_result(
Result::<_, ()>::Ok(v),
callback,
error,
),
error,
);
} else {
let _ = Channel::from_callback_fn(webview, callback)
.send(InvokeResponseBody::Raw(v.clone()));
}
}
InvokeResponse::Err(e) => responder_eval(
&webview,
crate::ipc::format_callback::format_result(
Result::<(), _>::Err(&e.0),
callback,
),
error,
),
)
}
}
InvokeResponse::Ok(InvokeResponseBody::Raw(v)) => {
if cfg!(target_os = "macos")
|| cfg!(target_os = "ios")
|| !can_use_channel_for_response
{
responder_eval(
&webview,
crate::ipc::format_callback::format_result(
Result::<_, ()>::Ok(v),
callback,
error,
),
error,
);
} else {
let _ = Channel::from_callback_fn(webview, callback)
.send(InvokeResponseBody::Raw(v.clone()));
}
}
InvokeResponse::Err(e) => responder_eval(
&webview,
crate::ipc::format_callback::format_result(
Result::<(), _>::Err(&e.0),
callback,
error,
),
}
error,
),
}
}),
);
@ -593,7 +589,7 @@ mod tests {
Default::default(),
Default::default(),
Default::default(),
(None, "".into()),
"".into(),
crate::generate_invoke_key().unwrap(),
);
@ -706,7 +702,7 @@ mod tests {
Default::default(),
Default::default(),
Default::default(),
(None, "".into()),
"".into(),
crate::generate_invoke_key().unwrap(),
);

View File

@ -22,7 +22,7 @@ use tauri_utils::{
use crate::{
app::{AppHandle, GlobalWebviewEventListener, GlobalWindowEventListener, OnPageLoad},
event::{assert_event_name_is_valid, Event, EventId, EventTarget, Listeners},
ipc::{Invoke, InvokeHandler, InvokeResponder, RuntimeAuthority},
ipc::{Invoke, InvokeHandler, RuntimeAuthority},
plugin::PluginStore,
utils::{config::Config, PackageInfo},
Assets, Context, Pattern, Runtime, StateManager, Window,
@ -254,7 +254,7 @@ impl<R: Runtime> AppManager<R> {
String,
crate::app::GlobalMenuEventListener<Window<R>>,
>,
(invoke_responder, invoke_initialization_script): (Option<Arc<InvokeResponder<R>>>, String),
invoke_initialization_script: String,
invoke_key: String,
) -> Self {
// generate a random isolation key at runtime
@ -276,7 +276,6 @@ impl<R: Runtime> AppManager<R> {
on_page_load,
uri_scheme_protocols: Mutex::new(uri_scheme_protocols),
event_listeners: Arc::new(webiew_event_listeners),
invoke_responder,
invoke_initialization_script,
invoke_key: invoke_key.clone(),
},
@ -731,7 +730,7 @@ mod test {
Default::default(),
Default::default(),
Default::default(),
(None, "".into()),
"".into(),
crate::generate_invoke_key().unwrap(),
);

View File

@ -21,7 +21,7 @@ use url::Url;
use crate::{
app::{GlobalWebviewEventListener, OnPageLoad, UriSchemeResponder, WebviewEvent},
ipc::{InvokeHandler, InvokeResponder},
ipc::InvokeHandler,
pattern::PatternJavascript,
sealed::ManagerBase,
webview::PageLoadPayload,
@ -75,8 +75,6 @@ pub struct WebviewManager<R: Runtime> {
/// Webview event listeners to all webviews.
pub event_listeners: Arc<Vec<GlobalWebviewEventListener<R>>>,
/// Responder for invoke calls.
pub invoke_responder: Option<Arc<InvokeResponder<R>>>,
/// The script that initializes the invoke system.
pub invoke_initialization_script: String,

View File

@ -1136,17 +1136,11 @@ fn main() {
return;
}
let custom_responder = self.manager().webview.invoke_responder.clone();
let resolver = InvokeResolver::new(
self.clone(),
Arc::new(Mutex::new(Some(Box::new(
#[allow(unused_variables)]
move |webview: Webview<R>, cmd, response, callback, error| {
if let Some(responder) = &custom_responder {
(responder)(&webview, &cmd, &response, callback, error);
}
responder(webview, cmd, response, callback, error);
},
)))),