Skip to content

Commit

Permalink
feat(ipc): preserve channel message order (#9070)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasfernog committed Mar 4, 2024
1 parent 6c06832 commit e62ca4e
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 7 deletions.
6 changes: 6 additions & 0 deletions .changes/preserve-channel-order.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"tauri": patch:enhance
"@tauri-apps/api": patch:enhance
---

Added a mechanism to preserve channel message order.
2 changes: 1 addition & 1 deletion core/tauri/scripts/bundle.global.js

Large diffs are not rendered by default.

14 changes: 11 additions & 3 deletions core/tauri/src/ipc/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{
collections::HashMap,
str::FromStr,
sync::{
atomic::{AtomicU32, Ordering},
atomic::{AtomicU32, AtomicUsize, Ordering},
Arc, Mutex,
},
};
Expand Down Expand Up @@ -132,18 +132,26 @@ impl Channel {
}

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| {
let data_id = CHANNEL_DATA_COUNTER.fetch_add(1, Ordering::Relaxed);

webview
.state::<ChannelDataIpcQueue>()
.0
.lock()
.unwrap()
.insert(data_id, body);

let i = counter.fetch_add(1, Ordering::Relaxed);

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
))
))?;

Ok(())
})
}

Expand Down
39 changes: 36 additions & 3 deletions tooling/api/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,44 @@ class Channel<T = unknown> {
#onmessage: (response: T) => void = () => {
// no-op
}
#nextMessageId = 0
#pendingMessages: Record<string, T> = {}

constructor() {
this.id = transformCallback((response: T) => {
this.#onmessage(response)
})
this.id = transformCallback(
({ 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) {
Expand Down

0 comments on commit e62ca4e

Please sign in to comment.