Google拡張機能と連携できるTauriベースのアプリを作った（Tauriで別アプリからアクセス出来るローカルサーバーを開く）

# はじめに
https://qiita.com/kft12/items/401697d44e56b50f5fc5

こちらの記事にて書いた通り、色々な経緯がありGoogle拡張機能からのPOSTリクエストを受け取れるElectronのアプリを作りました。

が、やっぱりTauriで作りたいなぁ・・といろいろ試行錯誤した結果、なんとか実装出来たのでメモも兼ねて残しておきます。

:::note warn
注意：Rustは素人以下レベルなのでかなり違和感のあるコードなどもあると思います。
ご容赦ください。
:::

# 連携方法
色々調べに調べた結果、Rustにて利用出来る`Actix-Web`というフレームワークが良いよ、ということでふんわり理解しました。

実装は下記の通りです。

```toml:Cargo.toml
[dependencies]
tauri = { version = "1", features = ["api-all"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
actix-web = "4" # 追加したのはこの2つ
actix-cors = "0.6.0-beta.4" # 追加したのはこの2つ
```

一応自分の中ではこういう認識である、ということをコメントとして残しておきます。
```rust:main.rs
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use std::sync::OnceLock;
use actix_cors::Cors;
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use tauri::{Manager, Window};

// 一度だけ初期化ができる変数として、アプリウィンドウを定義
static WINDOW: OnceLock<Window> = OnceLock::new();

fn main() {
    tauri::Builder::default()
    .setup(|app| {
        // このあたりで上で定義した変数に代入？
        let window = app.get_window("main").unwrap();
        _ = WINDOW.set(window);

        // 関数を定義する
        // 元々appが使いたくてこの中で定義したけど、結局WINDOWを使う形にしたからここで定義する意味はないかも・・？
        async fn add_alert(req_body: String) -> impl Responder {
            WINDOW.get()
                .expect("Window is avaliable")
                .emit("add-alert", req_body) // add-alertというイベント名で、リクエストボディをフロントエンドに送信
                .unwrap();
            HttpResponse::Ok().body("Hello World!")
        }

        tauri::async_runtime::spawn(
            HttpServer::new(|| {
                App::new()
                    .wrap(Cors::permissive())
                    .route("/", web::post().to(add_alert)) // ルートに対してポストが送られた場合にadd_alertで処理を行うよう設定
            })
            .bind(("127.0.0.1", 8081))? // サーバーの設定 ポート番号とかを変えられる
            .run()
        );
        Ok(())
    })
    .run(tauri::generate_context!())
    .expect("error while running tauri application");
}
```

```svelte:App.svelte
<script lang="ts">
    import { appWindow } from "@tauri-apps/api/window";
    import { onMount } from "svelte";

    onMount(async () => {
        // アラートを追加する
        await Promise.all([
            // main.rs側で指定したイベント名をlistenしておく
            appWindow.listen('add-alert', async(event) => {
                // アラートを追加
                const payload = event.payload as string;
                const jsonObj = JSON.parse(payload);

                // 後は好きに処理を出来る
            })
        ]);
    });
</script>
```

Google拡張機能は以前のものと同じです。
```javascript:extension.js
// Google拡張機能
function sendAlert(imgSrc, message) {
	const req = new XMLHttpRequest();
	req.open('POST', 'http://localhost:8081');
	req.setRequestHeader('Content-Type','application/json');

    // 通知の画像と文言を送信
	req.send(JSON.stringify({
		img: imgSrc
		,text: message
	}));
}
```

# Tauriに乗り換えて良かったこと
## メモリ使用量が1/20になった
Electronで作ったものは、平均してメモリ使用量が**60MB**だったのですが、Tauriのものは平均**3MB**です。
すごい。

まあぶっちゃけどちらにせよ大した負担ではないのですが・・。

## Svelteが導入しやすかった
ElectronにSvelteを導入する方法も当然あるっぽいのですが、自分が無知なためうまく導入出来ず。
その点Tauriはプロジェクトを作成するときに選ぶだけで良いのでお手軽ですね。

# おわりに
やっぱりプログラマーたるものトライアンドエラーが大事なんですね、多分。
だいぶ思っていた動きに近い物ができたので満足です。

それと、Rustが本当に全然わからん！
今まで使ってきた言語とそもそもの基本的な部分が違いすぎて、全く直感的に理解出来ません。
ちゃんと勉強しないとだめだな・・。