Skip to content

Commit

Permalink
refactor(core): remove responder from custom invoke systems (#11027)
Browse files Browse the repository at this point in the history
* refactor(core): remove responder from custom invoke systems

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

* fix tests
  • Loading branch information
lucasfernog authored Sep 16, 2024
1 parent e7fd676 commit 551e062
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 118 deletions.
5 changes: 5 additions & 0 deletions .changes/remove-invoke-system-responder.md
Original file line number Diff line number Diff line change
@@ -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.
17 changes: 3 additions & 14 deletions crates/tauri/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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,

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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.
///
Expand All @@ -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
}

Expand Down Expand Up @@ -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,
));

Expand Down
178 changes: 87 additions & 91 deletions crates/tauri/src/ipc/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand All @@ -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);
}
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 can_use_channel_for_response = cmd
!= crate::ipc::channel::FETCH_CHANNEL_DATA_COMMAND
&& !options.custom_protocol_ipc_blocked;
let _ = webview.eval(&eval_js);
}

#[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,
};
let can_use_channel_for_response = cmd
!= crate::ipc::channel::FETCH_CHANNEL_DATA_COMMAND
&& !options.custom_protocol_ipc_blocked;

#[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(),
};
#[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,
};

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,
),
#[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,
)
}
),
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,
),
}
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,
);
} 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,
),
);
} 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,
),
}
}),
);
Expand Down Expand Up @@ -593,7 +589,7 @@ mod tests {
Default::default(),
Default::default(),
Default::default(),
(None, "".into()),
"".into(),
crate::generate_invoke_key().unwrap(),
);

Expand Down Expand Up @@ -706,7 +702,7 @@ mod tests {
Default::default(),
Default::default(),
Default::default(),
(None, "".into()),
"".into(),
crate::generate_invoke_key().unwrap(),
);

Expand Down
7 changes: 3 additions & 4 deletions crates/tauri/src/manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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(),
},
Expand Down Expand Up @@ -731,7 +730,7 @@ mod test {
Default::default(),
Default::default(),
Default::default(),
(None, "".into()),
"".into(),
crate::generate_invoke_key().unwrap(),
);

Expand Down
4 changes: 1 addition & 3 deletions crates/tauri/src/manager/webview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,

Expand Down
6 changes: 0 additions & 6 deletions crates/tauri/src/webview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
},
)))),
Expand Down

0 comments on commit 551e062

Please sign in to comment.