From 380d1d4b25f756eb744acffc6e73c43031fcf06e Mon Sep 17 00:00:00 2001 From: ForgQi <34411314+ForgQi@users.noreply.github.com> Date: Fri, 18 Jul 2025 02:46:11 +0800 Subject: [PATCH] Update build workflow and improve Tauri sidecar handling Enhanced the GitHub Actions workflow for Windows builds, including dynamic sidecar binary handling and updated Node version specification. Upgraded stream-gears crate to version 1.0.0. Refactored Tauri app to improve sidecar process management, including encoding handling, process shutdown, and automatic startup/shutdown integration. Added readme field to pyproject.toml and redirected frontend to localhost in App.tsx. --- .github/workflows/pyinstaller-publish.yml | 57 +++++++++--- Cargo.lock | 2 +- crates/stream-gears/Cargo.toml | 2 +- pyproject.toml | 5 +- tauri-app/src-tauri/src/lib.rs | 102 ++++++++++++++++------ tauri-app/src/App.tsx | 2 +- 6 files changed, 122 insertions(+), 48 deletions(-) diff --git a/.github/workflows/pyinstaller-publish.yml b/.github/workflows/pyinstaller-publish.yml index 4c33abf..60e464a 100644 --- a/.github/workflows/pyinstaller-publish.yml +++ b/.github/workflows/pyinstaller-publish.yml @@ -7,12 +7,14 @@ on: jobs: build: + permissions: + contents: write runs-on: 'windows-latest' steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: lts/* - name: Build frontend run: | npm install @@ -22,23 +24,54 @@ jobs: python-version: '3.x' - uses: PyO3/maturin-action@v1 with: - command: develop + command: build args: --release - name: Build run: | python -m pip install --upgrade pip + pip install target/wheels/*.whl pip install pyinstaller pyinstaller biliup.spec + - name: Rename and move sidecar + run: | + # 动态获取rustc的target triple + $TARGET_TRIPLE = rustc -Vv | Select-String "host:" | ForEach-Object {$_.Line.split(" ")[1]} + echo "Target Triple: $TARGET_TRIPLE" + + # 创建目标目录 (如果不存在) + New-Item -ItemType Directory -Force -Path tauri-app/src-tauri/binaries + + # 假设的原始路径和新路径 + $SOURCE_PATH = "dist/biliup.exe" + $DESTINATION_PATH = "tauri-app/src-tauri/binaries/biliup-$TARGET_TRIPLE.exe" + + echo "Moving $SOURCE_PATH to $DESTINATION_PATH" + + # 使用PowerShell的Move-Item命令进行移动和重命名 + Move-Item -Path $SOURCE_PATH -Destination $DESTINATION_PATH + shell: pwsh # Optionally verify that it works (provided that it does not need user interaction) #- run: ./dist/your-code/your-code - - uses: actions/upload-artifact@v4 + - name: install Rust stable + uses: dtolnay/rust-toolchain@stable + - name: install frontend dependencies + run: | + cd tauri-app + npm install + - uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - path: dist/* - - name: Upload binaries to release - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} -# file: target/release/${{ matrix.artifact_name }} - file: dist/biliup.exe - asset_name: biliup_$tag.exe - tag: ${{ github.ref }} + tagName: ${{ github.ref }} # the action automatically replaces \_\_VERSION\_\_ with the app version. + +# - uses: actions/upload-artifact@v4 +# with: +# path: dist/* +# - name: Upload binaries to release +# uses: svenstaro/upload-release-action@v2 +# with: +# repo_token: ${{ secrets.GITHUB_TOKEN }} +## file: target/release/${{ matrix.artifact_name }} +# file: dist/biliup.exe +# asset_name: biliup_$tag.exe +# tag: ${{ github.ref }} diff --git a/Cargo.lock b/Cargo.lock index c4a37ce..aa607d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5289,7 +5289,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stream-gears" -version = "0.4.102" +version = "1.0.0" dependencies = [ "anyhow", "biliup", diff --git a/crates/stream-gears/Cargo.toml b/crates/stream-gears/Cargo.toml index 9568341..e888043 100644 --- a/crates/stream-gears/Cargo.toml +++ b/crates/stream-gears/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stream-gears" -version = "0.4.102" +version = "1.0.0" edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/pyproject.toml b/pyproject.toml index 1d1e721..d9983fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,7 @@ manifest-path = "crates/stream-gears/Cargo.toml" [project] name = "biliup" +readme = "README.md" authors = [{ name = "ForgQi" }] description = "stream download and upload" keywords = ["bilibili douyu huya"] @@ -46,10 +47,6 @@ dynamic = ["version"] [project.optional-dependencies] selenium = ["selenium >= 3.8.1"] -[project.readme] -file = "README.md" -content-type = "text/markdown" - [project.scripts] biliup = "biliup.__main__:arg_parser" diff --git a/tauri-app/src-tauri/src/lib.rs b/tauri-app/src-tauri/src/lib.rs index 7a53a27..d75ed2c 100644 --- a/tauri-app/src-tauri/src/lib.rs +++ b/tauri-app/src-tauri/src/lib.rs @@ -1,7 +1,8 @@ +use std::env; use std::sync::{Arc, Mutex}; -use tauri::{Emitter, Manager}; +use tauri::{Emitter, Manager, RunEvent}; +use tauri_plugin_shell::process::{CommandChild, CommandEvent, Encoding}; use tauri_plugin_shell::ShellExt; -use tauri_plugin_shell::process::{CommandChild, CommandEvent}; // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ #[tauri::command] @@ -9,7 +10,6 @@ fn greet(name: &str) -> String { format!("Hello, {}! You've been greeted from Rust!", name) } - // Helper function to spawn the sidecar and monitor its stdout/stderr fn spawn_and_monitor_sidecar(app_handle: tauri::AppHandle) -> Result<(), String> { // Check if a sidecar process already exists @@ -26,7 +26,7 @@ fn spawn_and_monitor_sidecar(app_handle: tauri::AppHandle) -> Result<(), String> // let (mut rx, mut _child) = sidecar_command // .spawn() // .expect("Failed to spawn sidecar"); - // + // // tauri::async_runtime::spawn(async move { // // 读取诸如 stdout 之类的事件 // while let Some(event) = rx.recv().await { @@ -39,26 +39,39 @@ fn spawn_and_monitor_sidecar(app_handle: tauri::AppHandle) -> Result<(), String> // } // } // }); - + // Spawn sidecar let sidecar_command = app_handle .shell() .sidecar("biliup") .map_err(|e| e.to_string())?; - let (mut rx, child) = sidecar_command.spawn().map_err(|e| e.to_string())?; + // 获取当前可执行文件的路径 + let exe_path = env::current_exe().unwrap(); + // 获取可执行文件所在的目录 + let exe_dir = exe_path.parent().unwrap(); + println!("[tauri] Sidecar directory: {}", exe_dir.display()); + let (mut rx, child) = sidecar_command + .current_dir(exe_dir) + // .env("PYTHONUTF8", "1") + .spawn() + .map_err(|e| e.to_string())?; // Store the child process in the app state if let Some(state) = app_handle.try_state::>>>() { + println!("child {:?}", child); + println!("pid {}", child.pid()); *state.lock().unwrap() = Some(child); } else { return Err("Failed to access app state".to_string()); } - + println!("[tauri] Sidecar started and running."); // Spawn an async task to handle sidecar communication tauri::async_runtime::spawn(async move { while let Some(event) = rx.recv().await { match event { CommandEvent::Stdout(line_bytes) => { - let line = String::from_utf8_lossy(&line_bytes); + let encoding = Encoding::for_label("GBK".as_ref()).unwrap(); + // let line = String::from_utf8_lossy(&line_bytes); + let line = encoding.decode_with_bom_removal(&line_bytes).0; println!("Sidecar stdout: {}", line); // Emit the line to the frontend app_handle @@ -83,7 +96,7 @@ fn spawn_and_monitor_sidecar(app_handle: tauri::AppHandle) -> Result<(), String> // Define a command to shutdown sidecar process #[tauri::command] -async fn shutdown_sidecar(app_handle: tauri::AppHandle) -> Result { +fn shutdown_sidecar(app_handle: &tauri::AppHandle) -> Result { println!("[tauri] Received command to shutdown sidecar."); // Access the sidecar process state if let Some(state) = app_handle.try_state::>>>() { @@ -94,39 +107,50 @@ async fn shutdown_sidecar(app_handle: tauri::AppHandle) -> Result // 这是在 Windows 上杀死进程及其所有子进程的最佳方式 println!("Using 'taskkill' on Windows to force kill process tree."); - kill_command = shell.command("taskkill") + kill_command = shell + .command("taskkill") .args(&["/F", "/T", "/PID", &pid.to_string()]) .spawn(); } match kill_command { Ok((mut rx, _)) => { - while let Some(event) = rx.recv().await { - match event { - CommandEvent::Stdout(line) => println!("Force kill stdout: {:?}", line), - CommandEvent::Stderr(line) => eprintln!("Force kill stderr: {:?}", line), - CommandEvent::Terminated(payload) => { - if payload.code == Some(0) { - println!("Sidecar (PID: {}) and its children force killed successfully.", pid); - } else { - // 在 Windows 上,如果进程已不存在,taskkill 会返回非0代码(如128),这是正常的。 - // 在 Linux/macOS 上,如果进程已不存在,kill/pkill 会报错,也是正常的。 - println!("Force kill command finished. Process was likely already dead."); + tauri::async_runtime::block_on(async move { + let encoding = Encoding::for_label("GBK".as_ref()).unwrap(); + while let Some(event) = rx.recv().await { + match event { + CommandEvent::Stdout(line) => println!( + "Force kill stdout: {:?}", + encoding.decode_with_bom_removal(&line).0 + ), + CommandEvent::Stderr(line) => eprintln!( + "Force kill stderr: {:?}", + encoding.decode_with_bom_removal(&line).0 + ), + CommandEvent::Terminated(payload) => { + if payload.code == Some(0) { + println!("Sidecar (PID: {}) and its children force killed successfully.", pid); + } else { + // 在 Windows 上,如果进程已不存在,taskkill 会返回非0代码(如128),这是正常的。 + // 在 Linux/macOS 上,如果进程已不存在,kill/pkill 会报错,也是正常的。 + println!("Force kill command finished. Process was likely already dead."); + } } - }, - _ => {} + _ => {} + } } - } - }, + }); + } Err(e) => { eprintln!("Failed to execute force kill command: {}", e); } } - + println!("[tauri] Sent 'sidecar shutdown' command to sidecar."); Ok("'sidecar shutdown' command sent.".to_string()) } else { @@ -146,12 +170,32 @@ fn start_sidecar(app_handle: tauri::AppHandle) -> Result { Ok("Sidecar spawned and monitoring started.".to_string()) } - #[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| { + // Store the initial sidecar process in the app state + app.manage(Arc::new(Mutex::new(None::))); + // Clone the app handle for use elsewhere + let app_handle = app.handle().clone(); + // Spawn the Python sidecar on startup + println!("[tauri] Creating sidecar..."); + spawn_and_monitor_sidecar(app_handle).ok(); + println!("[tauri] Sidecar spawned and monitoring started."); + + Ok(()) + }) .invoke_handler(tauri::generate_handler![greet]) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); + .build(tauri::generate_context!()) + .expect("error while running tauri application") + .run(|app_handle, event| match event { + // Ensure the Python sidecar is killed when the app is closed + RunEvent::ExitRequested { .. } => { + shutdown_sidecar(app_handle).expect("Failed to shutdown sidecar"); + println!("[tauri] Sidecar closed."); + } + _ => {} + }); } diff --git a/tauri-app/src/App.tsx b/tauri-app/src/App.tsx index 9855368..466aa0a 100644 --- a/tauri-app/src/App.tsx +++ b/tauri-app/src/App.tsx @@ -6,7 +6,7 @@ import "./App.css"; function App() { const [greetMsg, setGreetMsg] = useState(""); const [name, setName] = useState(""); - + window.location.replace("http://localhost:19159"); async function greet() { // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ setGreetMsg(await invoke("greet", { name }));