mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-02-06 13:17:02 +00:00
fix(api): use array for channel queueing (#12069)
This commit is contained in:
parent
231e9a5ee1
commit
a16796a555
5
.changes/api-channel-miss-events.md
Normal file
5
.changes/api-channel-miss-events.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tauri-apps/api": "patch:bug"
|
||||
---
|
||||
|
||||
Fix `Channel` never calls `onmessage` in some cases
|
||||
File diff suppressed because one or more lines are too long
@ -17,6 +17,7 @@ fn main() {
|
||||
"log_operation",
|
||||
"perform_request",
|
||||
"echo",
|
||||
"spam",
|
||||
])),
|
||||
)
|
||||
.expect("failed to run tauri-build");
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
},
|
||||
"allow-perform-request",
|
||||
"allow-echo",
|
||||
"allow-spam",
|
||||
"app-menu:default",
|
||||
"sample:allow-ping-scoped",
|
||||
"sample:global-scope",
|
||||
|
||||
11
examples/api/src-tauri/permissions/autogenerated/spam.toml
Normal file
11
examples/api/src-tauri/permissions/autogenerated/spam.toml
Normal file
@ -0,0 +1,11 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-spam"
|
||||
description = "Enables the spam command without any pre-configured scope."
|
||||
commands.allow = ["spam"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-spam"
|
||||
description = "Denies the spam command without any pre-configured scope."
|
||||
commands.deny = ["spam"]
|
||||
@ -3,7 +3,10 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::{command, ipc::CommandScope};
|
||||
use tauri::{
|
||||
command,
|
||||
ipc::{Channel, CommandScope},
|
||||
};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[allow(unused)]
|
||||
@ -28,7 +31,7 @@ pub fn log_operation(
|
||||
} else if !command_scope.allows().iter().any(|s| s.event == event) {
|
||||
Err("not allowed")
|
||||
} else {
|
||||
log::info!("{} {:?}", event, payload);
|
||||
log::info!("{event} {payload:?}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -40,7 +43,7 @@ pub struct ApiResponse {
|
||||
|
||||
#[command]
|
||||
pub fn perform_request(endpoint: String, body: RequestBody) -> ApiResponse {
|
||||
println!("{} {:?}", endpoint, body);
|
||||
println!("{endpoint} {body:?}");
|
||||
ApiResponse {
|
||||
message: "message response".into(),
|
||||
}
|
||||
@ -50,3 +53,11 @@ pub fn perform_request(endpoint: String, body: RequestBody) -> ApiResponse {
|
||||
pub fn echo(request: tauri::ipc::Request<'_>) -> tauri::ipc::Response {
|
||||
tauri::ipc::Response::new(request.body().clone())
|
||||
}
|
||||
|
||||
#[command]
|
||||
pub fn spam(channel: Channel<i32>) -> tauri::Result<()> {
|
||||
for i in 1..=1_000 {
|
||||
channel.send(i)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -145,7 +145,8 @@ pub fn run_app<R: Runtime, F: FnOnce(&App<R>) + Send + 'static>(
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
cmd::log_operation,
|
||||
cmd::perform_request,
|
||||
cmd::echo
|
||||
cmd::echo,
|
||||
cmd::spam,
|
||||
])
|
||||
.build(tauri::tauri_build_context!())
|
||||
.expect("error while building tauri application");
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { Channel, invoke } from '@tauri-apps/api/core'
|
||||
import { onMount, onDestroy } from 'svelte'
|
||||
|
||||
export let onMessage
|
||||
@ -46,6 +46,12 @@
|
||||
invoke('echo', [1, 2, 3]).then(onMessage).catch(onMessage)
|
||||
}
|
||||
|
||||
function spam() {
|
||||
const channel = new Channel()
|
||||
channel.onmessage = onMessage
|
||||
invoke('spam', { channel })
|
||||
}
|
||||
|
||||
function emitEvent() {
|
||||
webviewWindow.emit('js-event', 'this is the payload string')
|
||||
}
|
||||
@ -60,4 +66,5 @@
|
||||
Send event to Rust
|
||||
</button>
|
||||
<button class="btn" id="request" on:click={echo}> Echo </button>
|
||||
<button class="btn" id="request" on:click={spam}> Spam </button>
|
||||
</div>
|
||||
|
||||
@ -81,42 +81,31 @@ class Channel<T = unknown> {
|
||||
#onmessage: (response: T) => void = () => {
|
||||
// no-op
|
||||
}
|
||||
// the id is used as a mechanism to preserve message order
|
||||
#nextMessageId = 0
|
||||
#pendingMessages: Record<string, T> = {}
|
||||
#pendingMessages: T[] = []
|
||||
|
||||
constructor() {
|
||||
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
|
||||
// Process the message if we're at the right order
|
||||
if (id == this.#nextMessageId) {
|
||||
this.#onmessage(message)
|
||||
this.#nextMessageId += 1
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
this.#nextMessageId = nextId
|
||||
while (this.#nextMessageId in this.#pendingMessages) {
|
||||
const message = this.#pendingMessages[this.#nextMessageId]
|
||||
this.#onmessage(message)
|
||||
// eslint-disable-next-line @typescript-eslint/no-array-delete
|
||||
delete this.#pendingMessages[this.#nextMessageId]
|
||||
this.#nextMessageId += 1
|
||||
}
|
||||
} else {
|
||||
this.#pendingMessages[id.toString()] = message
|
||||
}
|
||||
// Queue the message if we're not
|
||||
else {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
this.#pendingMessages[id] = message
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user