added emit2 and emitTo2 instead

This commit is contained in:
Lucas Nogueira
2025-10-09 14:17:46 -03:00
parent 95f6c48dc0
commit 2ece5d7adf
6 changed files with 236 additions and 28 deletions

View File

@@ -2,4 +2,4 @@
"@tauri-apps/api": minor:feat
---
Allow sending raw Uint8Array/ArrayBuffer/number[] on the event emit and emitTo functions.
Optimize raw Uint8Array/ArrayBuffer/number[] payloads on the event system via the emit2 and emitTo2 functions.

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,4 @@
use serde::Deserialize;
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
@@ -38,49 +39,67 @@ async fn unlisten<R: Runtime>(
#[command(root = "crate")]
async fn emit<R: Runtime>(app: AppHandle<R>, request: Request<'_>) -> Result<()> {
let event = if let Some(event_header) = request
if let Some(event_header) = request
.headers()
.get(EVENT_NAME_HEADER_NAME)
.and_then(|v| v.to_str().ok())
{
EventName::new(event_header)?
let event = EventName::new(event_header)?;
match request.body() {
InvokeBody::Json(payload) => app.emit(event.as_str(), payload),
InvokeBody::Raw(payload) => app.emit_raw(event.as_str(), payload.clone()),
}
} else if let InvokeBody::Json(payload) = request.body() {
let args: EmitArgs = serde_json::from_value(payload.clone())?;
app.emit(args.event.as_str(), args.payload)
} else {
return Err(anyhow::anyhow!("missing event name header").into());
};
match request.body() {
InvokeBody::Json(payload) => app.emit(event.as_str(), payload),
InvokeBody::Raw(payload) => app.emit_raw(event.as_str(), payload.clone()),
Err(anyhow::anyhow!("unexpected emit request format").into())
}
}
#[derive(Deserialize)]
struct EmitArgs {
event: EventName,
payload: Option<serde_json::Value>,
}
#[command(root = "crate")]
async fn emit_to<R: Runtime>(app: AppHandle<R>, request: Request<'_>) -> Result<()> {
let event = if let Some(event_header) = request
if let Some(event_header) = request
.headers()
.get(EVENT_NAME_HEADER_NAME)
.and_then(|v| v.to_str().ok())
{
EventName::new(event_header)?
} else {
return Err(anyhow::anyhow!("missing event name header").into());
};
let event = EventName::new(event_header)?;
let target = if let Some(target_header) = request
.headers()
.get(EVENT_TARGET_HEADER_NAME)
.and_then(|v| v.to_str().ok())
{
serde_json::from_str::<EventTarget>(target_header)?
} else {
return Err(anyhow::anyhow!("missing event target header").into());
};
let target = if let Some(target_header) = request
.headers()
.get(EVENT_TARGET_HEADER_NAME)
.and_then(|v| v.to_str().ok())
{
serde_json::from_str::<EventTarget>(target_header)?
match request.body() {
InvokeBody::Json(payload) => app.emit_to(target, event.as_str(), payload),
InvokeBody::Raw(payload) => app.emit_raw_to(target, event.as_str(), payload.clone()),
}
} else if let InvokeBody::Json(payload) = request.body() {
let args: EmitToArgs = serde_json::from_value(payload.clone())?;
app.emit_to(args.target, args.event.as_str(), args.payload)
} else {
return Err(anyhow::anyhow!("missing event target header").into());
};
match request.body() {
InvokeBody::Json(payload) => app.emit_to(target, event.as_str(), payload),
InvokeBody::Raw(payload) => app.emit_raw_to(target, event.as_str(), payload.clone()),
Err(anyhow::anyhow!("unexpected emit request format").into())
}
}
#[derive(Deserialize)]
struct EmitToArgs {
event: EventName,
payload: Option<serde_json::Value>,
target: EventTarget,
}
#[command(root = "crate")]
fn fetch_payload(
request: Request<'_>,

View File

@@ -172,6 +172,8 @@ async function once<T>(
/**
* Emits an event to all {@link EventTarget|targets}.
*
* Prefer {@link emit2} to send binary data.
*
* @example
* ```typescript
* import { emit } from '@tauri-apps/api/event';
@@ -184,6 +186,26 @@ async function once<T>(
* @since 1.0.0
*/
async function emit<T>(event: string, payload?: T): Promise<void> {
await invoke('plugin:event|emit', { event, payload })
}
/**
* Emits an event to all {@link EventTarget|targets}.
*
* This function is similar to {@link emit} but it is optimized for binary payloads.
*
* @example
* ```typescript
* import { emit2 } from '@tauri-apps/api/event';
* await emit2('frontend-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*
* @since 2.10.0
*/
async function emit2<T>(event: string, payload?: T): Promise<void> {
await invoke('plugin:event|emit', payload as any, {
headers: { 'Tauri-Event-Name': event }
})
@@ -192,6 +214,8 @@ async function emit<T>(event: string, payload?: T): Promise<void> {
/**
* Emits an event to all {@link EventTarget|targets} matching the given target.
*
* Prefer {@link emitTo2} to send binary data.
*
* @example
* ```typescript
* import { emitTo } from '@tauri-apps/api/event';
@@ -208,6 +232,33 @@ async function emitTo<T>(
target: EventTarget | string,
event: string,
payload?: T
): Promise<void> {
const eventTarget: EventTarget =
typeof target === 'string' ? { kind: 'AnyLabel', label: target } : target
await invoke('plugin:event|emit_to', { event, payload, target: eventTarget })
}
/**
* Emits an event to all {@link EventTarget|targets} matching the given target.
*
* This function is similar to {@link emitTo} but it is optimized for binary payloads.
*
* @example
* ```typescript
* import { emitTo2 } from '@tauri-apps/api/event';
* await emitTo2('main', 'frontend-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param target Label of the target Window/Webview/WebviewWindow or raw {@link EventTarget} object.
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*
* @since 2.10.0
*/
async function emitTo2<T>(
target: EventTarget | string,
event: string,
payload?: T
): Promise<void> {
const eventTarget: EventTarget =
typeof target === 'string' ? { kind: 'AnyLabel', label: target } : target
@@ -215,7 +266,7 @@ async function emitTo<T>(
headers: {
'Tauri-Event-Name': event,
'Tauri-Event-Target': JSON.stringify(eventTarget)
},
}
})
}
@@ -228,4 +279,4 @@ export type {
Options
}
export { listen, once, emit, emitTo, TauriEvent }
export { listen, once, emit, emitTo, emit2, emitTo2, TauriEvent }

View File

@@ -25,7 +25,9 @@ import {
// imported for documentation purposes
type EventTarget,
emit,
emit2,
emitTo,
emitTo2,
listen,
once
} from './event'
@@ -313,6 +315,8 @@ class Webview {
/**
* Emits an event to all {@link EventTarget|targets}.
*
* Prefer {@link Webview.emit2} to send binary data.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
@@ -337,9 +341,40 @@ class Webview {
return emit<T>(event, payload)
}
/**
* Emits an event to all {@link EventTarget|targets}.
*
* This function is similar to {@link Webview.emit} but it is optimized for binary payloads.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().emit('webview-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*/
async emit2<T>(event: string, payload?: T): Promise<void> {
if (localTauriEvents.includes(event)) {
// eslint-disable-next-line
for (const handler of this.listeners[event] || []) {
handler({
event,
id: -1,
payload
})
}
return
}
return emit2<T>(event, payload)
}
/**
* Emits an event to all {@link EventTarget|targets} matching the given target.
*
* Prefer {@link Webview.emitTo2} to send binary data.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
@@ -369,6 +404,40 @@ class Webview {
return emitTo<T>(target, event, payload)
}
/**
* Emits an event to all {@link EventTarget|targets} matching the given target.
*
* This function is similar to {@link Webview.emitTo} but it is optimized for binary payloads.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().emitTo('main', 'webview-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param target Label of the target Window/Webview/WebviewWindow or raw {@link EventTarget} object.
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*/
async emitTo2<T>(
target: string | EventTarget,
event: string,
payload?: T
): Promise<void> {
if (localTauriEvents.includes(event)) {
// eslint-disable-next-line
for (const handler of this.listeners[event] || []) {
handler({
event,
id: -1,
payload
})
}
return
}
return emitTo2<T>(target, event, payload)
}
/** @ignore */
_handleTauriEvent<T>(event: string, handler: EventCallback<T>): boolean {
if (localTauriEvents.includes(event)) {

View File

@@ -30,7 +30,9 @@ import {
// imported for documentation purposes
type EventTarget,
emit,
emit2,
emitTo,
emitTo2,
listen,
once
} from './event'
@@ -437,6 +439,9 @@ class Window {
/**
* Emits an event to all {@link EventTarget|targets}.
*
* Prefer {@link Window.emit2} to send binary data.
*
* @example
* ```typescript
* import { getCurrentWindow } from '@tauri-apps/api/window';
@@ -461,9 +466,40 @@ class Window {
return emit<T>(event, payload)
}
/**
* Emits an event to all {@link EventTarget|targets}.
*
* This function is similar to {@link Window.emit} but it is optimized for binary payloads.
*
* @example
* ```typescript
* import { getCurrentWindow } from '@tauri-apps/api/window';
* await getCurrentWindow().emit('window-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*/
async emit2<T>(event: string, payload?: T): Promise<void> {
if (localTauriEvents.includes(event)) {
// eslint-disable-next-line
for (const handler of this.listeners[event] || []) {
handler({
event,
id: -1,
payload
})
}
return
}
return emit2<T>(event, payload)
}
/**
* Emits an event to all {@link EventTarget|targets} matching the given target.
*
* Prefer {@link Window.emitTo2} to send binary data.
*
* @example
* ```typescript
* import { getCurrentWindow } from '@tauri-apps/api/window';
@@ -492,6 +528,39 @@ class Window {
return emitTo<T>(target, event, payload)
}
/**
* Emits an event to all {@link EventTarget|targets} matching the given target.
*
* This function is similar to {@link Window.emitTo} but it is optimized for binary payloads.
*
* @example
* ```typescript
* import { getCurrentWindow } from '@tauri-apps/api/window';
* await getCurrentWindow().emit('main', 'window-loaded', { loggedIn: true, token: 'authToken' });
* ```
* @param target Label of the target Window/Webview/WebviewWindow or raw {@link EventTarget} object.
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*/
async emitTo2<T>(
target: string | EventTarget,
event: string,
payload?: T
): Promise<void> {
if (localTauriEvents.includes(event)) {
// eslint-disable-next-line security/detect-object-injection
for (const handler of this.listeners[event] || []) {
handler({
event,
id: -1,
payload
})
}
return
}
return emitTo2<T>(target, event, payload)
}
/** @ignore */
_handleTauriEvent<T>(event: string, handler: EventCallback<T>): boolean {
if (localTauriEvents.includes(event)) {