Rust からフロントエンドへイベントを送る

Recipe ID: rust-010

Rust 側の何らかの処理(タイマー、バックグラウンドでの長い処理、システムからの通知など)が完了したときに、サーバープッシュのようにフロントエンドへ通知を送りたいことがあります。

Tauri では「イベント(Event)」という仕組みを使って、双方向にメッセージを送ることができます。
ここでは Rust から発行 (emit) し、フロントエンドで受信 (listen) する方法を解説します。

1. Rust 側でイベントを発行する (emit)

tauri::Emitter トレイトにより、AppHandleWebviewWindow からイベントを送信できます。

use tauri::{AppHandle, Emitter};
use serde::Serialize;

#[derive(Clone, Serialize)]
struct DownloadProgress {
    percent: u32,
    message: String,
}

// コマンドや別スレッドから呼び出す関数例
fn notify_download_start(app: &AppHandle) {
    let payload = DownloadProgress {
        percent: 0,
        message: "ダウンロードを開始しました".into(),
    };

    // "download-status" というイベント名で、全ウィンドウに向けて送信
    // 第2引数は Serialize 可能なデータであれば何でもOK
    if let Err(e) = app.emit("download-status", payload) {
        eprintln!("イベント送信失敗: {}", e);
    }
}

2. フロントエンド側で受信する (listen)

@tauri-apps/api/eventlisten 関数を使います。
listen 関数は Promise<UnlistenFn> を返します。不要になったら unlisten() を呼んでリソースを解放するのがお作法です。

import { listen, UnlistenFn } from '@tauri-apps/api/event';

// イベントのデータ型を定義しておくと便利
interface DownloadProgress {
  percent: number;
  message: string;
}

async function setupListener() {
  // 'download-status' イベントをリッスン
  // ジェネリクス <DownloadProgress> を指定すると payload の型推論が効きます
  const unlisten: UnlistenFn = await listen<DownloadProgress>('download-status', (event) => {
      console.log('イベント受信:', event);
      // event.payload は DownloadProgress 型として扱える
      console.log(`進捗: ${event.payload.percent}% - ${event.payload.message}`);
  });

  // リスナーを解除したい場合に呼び出す
  // unlisten();
}

// アプリ起動時などに呼び出す
setupListener();

注意点

  • イベント名: 任意の文字列を使えますが、tauri:// で始まる名前は予約されているため避けてください。
  • グローバル送信: app.emit() は開いている全てのウィンドウに向けて送信されます。
  • 個別送信: 特定のウィンドウにだけ送りたい場合は、window.emit() または app.emit_to("label", ...) を使います。