mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-08-17 11:50:26 +03:00
feat(ipc): preserve channel message order (#9070)
This commit is contained in:
parent
6c06832246
commit
e62ca4ee95
6
.changes/preserve-channel-order.md
Normal file
6
.changes/preserve-channel-order.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"tauri": patch:enhance
|
||||||
|
"@tauri-apps/api": patch:enhance
|
||||||
|
---
|
||||||
|
|
||||||
|
Added a mechanism to preserve channel message order.
|
File diff suppressed because one or more lines are too long
@ -6,7 +6,7 @@ use std::{
|
|||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicU32, Ordering},
|
atomic::{AtomicU32, AtomicUsize, Ordering},
|
||||||
Arc, Mutex,
|
Arc, Mutex,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -132,18 +132,26 @@ impl Channel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_callback_fn<R: Runtime>(webview: Webview<R>, callback: CallbackFn) -> Self {
|
pub(crate) fn from_callback_fn<R: Runtime>(webview: Webview<R>, callback: CallbackFn) -> Self {
|
||||||
|
let counter = AtomicUsize::new(0);
|
||||||
|
|
||||||
Channel::new_with_id(callback.0, move |body| {
|
Channel::new_with_id(callback.0, move |body| {
|
||||||
let data_id = CHANNEL_DATA_COUNTER.fetch_add(1, Ordering::Relaxed);
|
let data_id = CHANNEL_DATA_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
webview
|
webview
|
||||||
.state::<ChannelDataIpcQueue>()
|
.state::<ChannelDataIpcQueue>()
|
||||||
.0
|
.0
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.insert(data_id, body);
|
.insert(data_id, body);
|
||||||
|
|
||||||
|
let i = counter.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
webview.eval(&format!(
|
webview.eval(&format!(
|
||||||
"window.__TAURI_INTERNALS__.invoke('{FETCH_CHANNEL_DATA_COMMAND}', null, {{ headers: {{ '{CHANNEL_ID_HEADER_NAME}': '{data_id}' }} }}).then(window['_' + {}]).catch(console.error)",
|
"window.__TAURI_INTERNALS__.invoke('{FETCH_CHANNEL_DATA_COMMAND}', null, {{ headers: {{ '{CHANNEL_ID_HEADER_NAME}': '{data_id}' }} }}).then((response) => window['_' + {}]({{ message: response, id: {i} }})).catch(console.error)",
|
||||||
callback.0
|
callback.0
|
||||||
))
|
))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,11 +31,44 @@ class Channel<T = unknown> {
|
|||||||
#onmessage: (response: T) => void = () => {
|
#onmessage: (response: T) => void = () => {
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
#nextMessageId = 0
|
||||||
|
#pendingMessages: Record<string, T> = {}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.id = transformCallback((response: T) => {
|
this.id = transformCallback(
|
||||||
this.#onmessage(response)
|
({ message, id }: { message: T; id: number }) => {
|
||||||
})
|
// the id is used as a mechanism to preserve message order
|
||||||
|
if (id === this.#nextMessageId) {
|
||||||
|
this.#nextMessageId = id + 1
|
||||||
|
this.#onmessage(message)
|
||||||
|
|
||||||
|
// process pending messages
|
||||||
|
const pendingMessageIds = Object.keys(this.#pendingMessages)
|
||||||
|
if (pendingMessageIds.length > 0) {
|
||||||
|
let nextId = id + 1
|
||||||
|
for (const pendingId of pendingMessageIds.sort()) {
|
||||||
|
// if we have the next message, process it
|
||||||
|
if (parseInt(pendingId) === nextId) {
|
||||||
|
// eslint-disable-next-line security/detect-object-injection
|
||||||
|
const message = this.#pendingMessages[pendingId]
|
||||||
|
// eslint-disable-next-line security/detect-object-injection
|
||||||
|
delete this.#pendingMessages[pendingId]
|
||||||
|
|
||||||
|
this.#onmessage(message)
|
||||||
|
|
||||||
|
// move the id counter to the next message to check
|
||||||
|
nextId += 1
|
||||||
|
} else {
|
||||||
|
// we do not have the next message, let's wait
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.#pendingMessages[id.toString()] = message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
set onmessage(handler: (response: T) => void) {
|
set onmessage(handler: (response: T) => void) {
|
||||||
|
Loading…
Reference in New Issue
Block a user