From c5dc23bf9ae30b9f1ae1298b62e0c3641cff693c Mon Sep 17 00:00:00 2001 From: imbytecat Date: Fri, 16 Jan 2026 20:14:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E9=A1=B5=E4=B8=8ENitro=E4=BE=A7=E8=BD=A6?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E8=87=AA=E5=8A=A8=E5=90=AF=E5=8A=A8=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加启动加载页面,包含旋转动画和动态点状提示效果。 - 忽略 binaries 目录下所有文件,但保留 .gitignore 文件本身。 - 添加对二进制文件 binaries/nitro-server 的执行权限允许,启用侧车模式。 - 添加对 shell 插件和相关依赖的支持,包括 os_pipe、shared_child 和 signal-hook 等库,以增强 Tauri 应用的子进程管理与系统交互能力。 - 添加 shell 插件和异步网络支持以增强应用功能 - 添加 Nitro sidecar 服务自动启动功能,包括端口检测、服务器就绪监听及超时处理,并在启动成功后自动创建主窗口。 - 移除窗口配置并添加外部二进制文件路径配置 --- loading.html | 67 ++++++++++++++++++++++ src-tauri/Cargo.lock | 74 +++++++++++++++++++++++++ src-tauri/Cargo.toml | 2 + src-tauri/binaries/.gitignore | 2 + src-tauri/capabilities/default.json | 11 +++- src-tauri/src/lib.rs | 86 +++++++++++++++++++++++++++++ src-tauri/tauri.conf.json | 11 ++-- 7 files changed, 245 insertions(+), 8 deletions(-) create mode 100644 loading.html create mode 100644 src-tauri/binaries/.gitignore diff --git a/loading.html b/loading.html new file mode 100644 index 0000000..e2b1388 --- /dev/null +++ b/loading.html @@ -0,0 +1,67 @@ + + + + + + 启动中... + + + +
+
+

正在启动应用

+

请稍候

+
+ + diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 314ad0c..8956323 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -791,6 +791,15 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "endi" version = "1.1.1" @@ -2299,6 +2308,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "os_pipe" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "pango" version = "0.18.3" @@ -3190,12 +3209,44 @@ dependencies = [ "digest", ] +[[package]] +name = "shared_child" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7" +dependencies = [ + "libc", + "sigchld", + "windows-sys 0.60.2", +] + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "sigchld" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1" +dependencies = [ + "libc", + "os_pipe", + "signal-hook", +] + +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -3563,6 +3614,8 @@ dependencies = [ "tauri", "tauri-build", "tauri-plugin-opener", + "tauri-plugin-shell", + "tokio", ] [[package]] @@ -3618,6 +3671,27 @@ dependencies = [ "zbus", ] +[[package]] +name = "tauri-plugin-shell" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39b76f884a3937e04b631ffdc3be506088fa979369d25147361352f2f352e5ed" +dependencies = [ + "encoding_rs", + "log", + "open", + "os_pipe", + "regex", + "schemars 0.8.22", + "serde", + "serde_json", + "shared_child", + "tauri", + "tauri-plugin", + "thiserror 2.0.17", + "tokio", +] + [[package]] name = "tauri-runtime" version = "2.9.2" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 94ef6e7..1528511 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -20,6 +20,8 @@ tauri-build = { version = "2", features = [] } [dependencies] tauri = { version = "2", features = [] } tauri-plugin-opener = "2" +tauri-plugin-shell = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" +tokio = { version = "1", features = ["net"] } diff --git a/src-tauri/binaries/.gitignore b/src-tauri/binaries/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/src-tauri/binaries/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 4cdbf49..e847cbb 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -5,6 +5,15 @@ "windows": ["main"], "permissions": [ "core:default", - "opener:default" + "opener:default", + { + "identifier": "shell:allow-execute", + "allow": [ + { + "name": "binaries/nitro-server", + "sidecar": true + } + ] + } ] } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 4a277ef..bcc634c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,13 +1,99 @@ +use tauri_plugin_shell::ShellExt; +use tauri_plugin_shell::process::CommandEvent; +use std::time::Duration; + // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ #[tauri::command] fn greet(name: &str) -> String { format!("Hello, {}! You've been greeted from Rust!", name) } +// 检查端口是否可用 +async fn is_port_available(port: u16) -> bool { + tokio::net::TcpListener::bind(format!("127.0.0.1:{}", port)) + .await + .is_ok() +} + +// 查找可用端口 +async fn find_available_port(start: u16) -> u16 { + for port in start..start + 100 { + if is_port_available(port).await { + return port; + } + } + start // 回退到起始端口 +} + #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() .plugin(tauri_plugin_opener::init()) + .plugin(tauri_plugin_shell::init()) + .setup(|app| { + let app_handle = app.handle().clone(); + + // 异步启动 Nitro sidecar + tauri::async_runtime::spawn(async move { + // 查找可用端口 + let port = find_available_port(3000).await; + println!("使用端口: {}", port); + + // 启动 sidecar + let sidecar = app_handle + .shell() + .sidecar("nitro-server") + .expect("无法找到 nitro-server sidecar") + .env("NITRO_PORT", port.to_string()); + + let (mut rx, mut _child) = sidecar.spawn().expect("启动 sidecar 失败"); + + // 监听 stdout,等待服务器就绪信号 + let start_time = std::time::Instant::now(); + let timeout = Duration::from_secs(5); + let mut server_ready = false; + + while let Some(event) = rx.recv().await { + if let CommandEvent::Stdout(line) = event { + let output = String::from_utf8_lossy(&line); + println!("Nitro: {}", output); + + // 检测服务器启动成功的标志 + if output.contains("Listening on:") || output.contains("localhost") { + server_ready = true; + println!("✓ Nitro 服务器启动成功!"); + + // 创建主窗口 + let url = format!("http://localhost:{}", port); + tauri::WebviewWindowBuilder::new( + &app_handle, + "main", + tauri::WebviewUrl::External(url.parse().unwrap()) + ) + .title("Nitro Application") + .inner_size(1200.0, 800.0) + .build() + .expect("创建窗口失败"); + + break; + } + } + + // 超时检查 + if start_time.elapsed() > timeout { + eprintln!("✗ 启动超时:Nitro 服务器未能在 5 秒内启动"); + break; + } + } + + if !server_ready { + eprintln!("✗ Nitro 服务器启动失败"); + std::process::exit(1); + } + }); + + Ok(()) + }) .invoke_handler(tauri::generate_handler![greet]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index e2f6e57..3cb8041 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -11,13 +11,7 @@ }, "app": { "withGlobalTauri": true, - "windows": [ - { - "title": "tauri-demo", - "width": 800, - "height": 600 - } - ], + "windows": [], "security": { "csp": null } @@ -31,6 +25,9 @@ "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico" + ], + "externalBin": [ + "binaries/nitro-server" ] } }