tauri-apps / tauri

Build smaller, faster, and more secure desktop and mobile applications with a web frontend.
https://tauri.app
Apache License 2.0
85.73k stars 2.6k forks source link

[bug] v2 Event system: AnyLabel isn't handled correct #11561

Closed Mikkel-T closed 3 weeks ago

Mikkel-T commented 4 weeks ago

Describe the bug

The new event system, which primarily relies on targets to work, has some major flaws when it comes to handling these targets. Specifically targets of the kind AnyLabel, which is the default when just adding a string as target in both emitTo and listen.

For example, if a listener is set with the target "main", and emitTo("main", "eventName", "payload") is run, the listener will not be triggered.

I have tried to trace this behavior back to the source, and have stumbled upon this snippet from the implementation of the emit_to function in Rust.

// https://github.com/tauri-apps/tauri/blob/12ffc19ce08eeafdedc65207f312432aa2cf9c84/crates/tauri/src/manager/mod.rs#L590-L606
match target {
  // if targeting all, emit to all using emit without filter
  EventTarget::Any => self.emit(event, payload),

  // if targeting any label, emit using emit_filter and filter labels
  EventTarget::AnyLabel {
    label: target_label,
  } => self.emit_filter(event, payload, |t| match t {
    EventTarget::Window { label }
    | EventTarget::Webview { label }
    | EventTarget::WebviewWindow { label } => label == &target_label,
    _ => false,
  }),

  // otherwise match same target
  _ => self.emit_filter(event, payload, |t| t == &target),
}

Here, target is the target set in emit_to. When this is of the kind AnyLabel, the code will enter the second match, where it checks for t which is the listener target. It checks if t is of kind Window, Webview or WebviewWindow, none of which apply to AnyLabel by which it will return false when the listener is initialized without a specific kind.

If a kind has been specified for emit_to, it will go to the bottom line, and only match the same targets. Again, if the listener is initialized without a specific kind, and therefore gets the kind AnyLabel, it will not trigger the listener.

Reproduction

No response

Expected behavior

As far as I understand it, the expected behaviour would be to let AnyLabel serve as a "wildcard" for both emitTo and listen. So if any of the two are of the kind AnyLabel, any event with a label would be served between the two.

Full tauri info output

[✔] Environment
    - OS: Windows 10.0.22631 x86_64 (X64)
    ✔ WebView2: 130.0.2849.56
    ✔ MSVC: Visual Studio Community 2022
    ✔ rustc: 1.82.0 (f6e511eec 2024-10-15)
    ✔ cargo: 1.82.0 (8f40fc59f 2024-08-21)
    ✔ rustup: 1.27.1 (54dd3d00f 2024-04-24)
    ✔ Rust toolchain: stable-x86_64-pc-windows-msvc (default)
    - node: 20.15.1
    - yarn: 4.5.1
    - npm: 10.7.0
    - deno: deno 2.0.4

[-] Packages
    - tauri 🦀: 2.0.6
    - tauri-build 🦀: 2.0.2
    - wry 🦀: 0.46.3
    - tao 🦀: 0.30.5
    - @tauri-apps/api : 2.0.3
    - @tauri-apps/cli : 2.0.5

[-] Plugins
    - tauri-plugin-dialog 🦀: 2.0.3
    - @tauri-apps/plugin-dialog : 2.0.1
    - tauri-plugin-fs 🦀: 2.0.3
    - @tauri-apps/plugin-fs : 2.0.1
    - tauri-plugin-process 🦀: 2.0.1
    - @tauri-apps/plugin-process : 2.0.0
    - tauri-plugin-http 🦀: 2.0.3
    - @tauri-apps/plugin-http : 2.0.1

[-] App
    - build-type: bundle
    - CSP: unset
    - frontendDist: ../dist
    - devUrl: http://localhost:4321/
    - framework: Svelte
    - bundler: Rollup

Stack trace

No response

Additional context

I would be willing to work on a PR fixing this issue, but I would like to discuss the exact issue and expected behavior in depth before starting to change things in the event API.

amrbashir commented 4 weeks ago

@Mikkel-T thank you for the detailed bug and tracing, please feel free to open a PR.

Mikkel-T commented 3 weeks ago

I will definitely be doing so! But before I start, I would like to ensure that my implementation is going to align with the intended behaviour.

From my understanding, there are two main scenarios to consider:

  1. Emitter emitting an event to an AnyLabel target
  2. Listener listening to an AnyLabel target

There are currently four target kinds that support a label: Window, Webview, WebviewWindow and AnyLabel.

Expected behavior

For the first scenario, I expect that an event emitted to a target of kind AnyLabel should invoke listeners associated with any of the specified kinds. For example:

emitTo({kind: "AnyLabel", label: "main"}, "event", "payload");

// The following listeners should be invoked by this event:
listen("event", () => {}, {target: {kind: "Window", label: "main"}});
listen("event", () => {}, {target: {kind: "Webview", label: "main"}});
listen("event", () => {}, {target: {kind: "WebviewWindow", label: "main"}});
listen("event", () => {}, {target: {kind: "AnyLabel", label: "main"}});
listen("event", () => {}, {target: "main"}); // Default is AnyLabel

For the second scenario, I believe that a listener initialized with a target of kind AnyLabel should be invoked when receiving an event from any of the specified kinds:

listen("event", () => {}, {target: {kind: "AnyLabel", label: "main"}});

// The following events should invoke this listener:
emitTo({kind: "Window", label: "main"}, "event", "payload");
emitTo({kind: "Webview", label: "main"}, "event", "payload");
emitTo({kind: "WebviewWindow", label: "main"}, "event", "payload");
emitTo({kind: "AnyLabel", label: "main"}, "event", "payload");
emitTo("main", "event", "payload"); // Default is AnyLabel

Could you please confirm if my understanding is correct? I want to ensure that I’m on the right track before proceeding with a PR.