Skip to content

Commit 94b77b3

Browse files
fix: use format_callback::format_raw for channels (#13288)
* fix it * Create change-pr-13288.md * fixes * fixes * fix .change
1 parent 527bf00 commit 94b77b3

File tree

3 files changed

+32
-20
lines changed

3 files changed

+32
-20
lines changed

.changes/change-pr-13288.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": 'patch:bug'
3+
---
4+
5+
Prevent the JavaScript runtime crashing when channel events fire in a webview that no longer has callbacks for the channel.

crates/tauri/src/ipc/channel.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ use crate::{
2020
Manager, Runtime, State, Webview,
2121
};
2222

23-
use super::{CallbackFn, InvokeError, InvokeResponseBody, IpcResponse, Request, Response};
23+
use super::{
24+
format_callback, CallbackFn, InvokeError, InvokeResponseBody, IpcResponse, Request, Response,
25+
};
2426

2527
pub const IPC_PAYLOAD_PREFIX: &str = "__CHANNEL__:";
2628
// TODO: Change this to `channel` in v3
@@ -149,15 +151,14 @@ impl JavaScriptChannelId {
149151
match body {
150152
// Don't go through the fetch process if the payload is small
151153
InvokeResponseBody::Json(string) if string.len() < MAX_JSON_DIRECT_EXECUTE_THRESHOLD => {
152-
webview.eval(format!(
153-
"window['_{callback_id}']({{ message: {string}, index: {current_index} }})"
154+
webview.eval(format_callback::format_raw_js(
155+
callback_id,
156+
&format!("{{ message: {string}, index: {current_index} }}"),
154157
))?;
155158
}
156159
InvokeResponseBody::Raw(bytes) if bytes.len() < MAX_RAW_DIRECT_EXECUTE_THRESHOLD => {
157160
let bytes_as_json_array = serde_json::to_string(&bytes)?;
158-
webview.eval(format!(
159-
"window['_{callback_id}']({{ message: new Uint8Array({bytes_as_json_array}).buffer, index: {current_index} }})",
160-
))?;
161+
webview.eval(format_callback::format_raw_js(callback_id, &format!("{{ message: new Uint8Array({bytes_as_json_array}).buffer, index: {current_index} }}")))?;
161162
}
162163
// use the fetch API to speed up larger response payloads
163164
_ => {
@@ -180,8 +181,9 @@ impl JavaScriptChannelId {
180181
}),
181182
Some(Box::new(move || {
182183
let current_index = counter_clone.load(Ordering::Relaxed);
183-
let _ = webview_clone.eval(format!(
184-
"window['_{callback_id}']({{ end: true, index: {current_index} }})",
184+
let _ = webview_clone.eval(format_callback::format_raw_js(
185+
callback_id,
186+
&format!("{{ end: true, index: {current_index} }}"),
185187
));
186188
})),
187189
)
@@ -243,12 +245,13 @@ impl<TSend> Channel<TSend> {
243245
match body {
244246
// Don't go through the fetch process if the payload is small
245247
InvokeResponseBody::Json(string) if string.len() < MAX_JSON_DIRECT_EXECUTE_THRESHOLD => {
246-
webview.eval(format!("window['_{callback_id}']({string})"))?;
248+
webview.eval(format_callback::format_raw_js(callback_id, &string))?;
247249
}
248250
InvokeResponseBody::Raw(bytes) if bytes.len() < MAX_RAW_DIRECT_EXECUTE_THRESHOLD => {
249251
let bytes_as_json_array = serde_json::to_string(&bytes)?;
250-
webview.eval(format!(
251-
"window['_{callback_id}'](new Uint8Array({bytes_as_json_array}).buffer)",
252+
webview.eval(format_callback::format_raw_js(
253+
callback_id,
254+
&format!("new Uint8Array({bytes_as_json_array}).buffer"),
252255
))?;
253256
}
254257
// use the fetch API to speed up larger response payloads

crates/tauri/src/ipc/format_callback.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,22 @@ pub fn format<T: Serialize>(function_name: CallbackFn, arg: &T) -> crate::Result
9292
/// See [json-parse-benchmark](https://github.com/GoogleChromeLabs/json-parse-benchmark).
9393
pub fn format_raw(function_name: CallbackFn, json_string: String) -> crate::Result<String> {
9494
serialize_js_with(json_string, Default::default(), |arg| {
95-
format!(
96-
r#"
97-
if (window["_{fn}"]) {{
98-
window["_{fn}"]({arg})
99-
}} else {{
100-
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.")
101-
}}"#,
102-
fn = function_name.0
103-
)
95+
format_raw_js(function_name.0, arg)
10496
})
10597
}
10698

99+
/// Formats a callback function invocation, properly accounting for error handling.
100+
pub fn format_raw_js(id: u32, js: &str) -> String {
101+
format!(
102+
r#"
103+
if (window["_{id}"]) {{
104+
window["_{id}"]({js})
105+
}} else {{
106+
console.warn("[TAURI] Couldn't find callback id {id} in window. This happens when the app is reloaded while Rust is running an asynchronous operation.")
107+
}}"#
108+
)
109+
}
110+
107111
/// Formats a serializable Result type to its Promise response.
108112
///
109113
/// See [`format_result_raw`] for more information.

0 commit comments

Comments
 (0)