From 2bb24799f3762a330ec562960b38a387619128ea Mon Sep 17 00:00:00 2001 From: Huakun Shen Date: Fri, 10 Jan 2025 20:55:23 -0500 Subject: [PATCH] fix: file transfer ip bug When sending to non-localhost host, will fail. grpc server somehow cannot get client ip. Modified grpc proto to send a src ip. --- Cargo.lock | 38 +++++++++++++++++++ .../app/extension/file-transfer/+page.svelte | 15 +++++--- packages/grpc/protos/file-transfer.proto | 7 ++-- packages/tauri-plugins/jarvis/Cargo.toml | 1 + .../jarvis/src/commands/file_transfer.rs | 21 ++++++++-- .../jarvis/src/server/grpc/file_transfer.rs | 18 +++++---- 6 files changed, 80 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2ddc826..4b00d65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4000,6 +4000,18 @@ dependencies = [ "num-traits", ] +[[package]] +name = "local-ip-address" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3669cf5561f8d27e8fc84cc15e58350e70f557d4d65f70e3154e54cd2f8e1782" +dependencies = [ + "libc", + "neli", + "thiserror 1.0.66", + "windows-sys 0.59.0", +] + [[package]] name = "localauthentication-rs" version = "0.1.0" @@ -4322,6 +4334,31 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "neli" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43" +dependencies = [ + "byteorder", + "libc", + "log", + "neli-proc-macros", +] + +[[package]] +name = "neli-proc-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4" +dependencies = [ + "either", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", +] + [[package]] name = "network-interface" version = "1.1.4" @@ -7476,6 +7513,7 @@ dependencies = [ "futures-util", "grpc", "ico", + "local-ip-address", "log", "mac-security-rs", "mdns-sd", diff --git a/apps/desktop/src/routes/app/extension/file-transfer/+page.svelte b/apps/desktop/src/routes/app/extension/file-transfer/+page.svelte index 647f0ac..77f1dfc 100644 --- a/apps/desktop/src/routes/app/extension/file-transfer/+page.svelte +++ b/apps/desktop/src/routes/app/extension/file-transfer/+page.svelte @@ -57,16 +57,21 @@ unlistenReq = await listen("file-transfer-request", async (e) => { console.log(e) const confirmed = await confirm( - `Download files (${e.payload.totalFiles} files, ${prettyBytes(e.payload.totalBytes)})?` + `Download files (${e.payload.totalFiles} files, ${prettyBytes(e.payload.totalBytes)}) from ${e.payload.ip}?` ) if (!confirmed) return downloadFiles(e.payload, await path.downloadDir(), (progress) => { progressMap[e.payload.code] = progress console.log(progress) - }).finally(() => { - console.log("finally clean", e.payload.code) - delete progressMap[e.payload.code] }) + .catch((err) => { + console.error("Fail to download files", err) + toast.error("Fail to download files", { description: err.message }) + }) + .finally(() => { + console.log("finally clean", e.payload.code) + delete progressMap[e.payload.code] + }) }) }) @@ -85,7 +90,7 @@ } function sendFile(peer: MdnsServiceInfo, files: string[]) { - console.log(peer, files) + // console.log(peer.addresses[0], peer.port, peer.sslCert, files) localNetSendFile(peer.addresses[0], peer.port, peer.sslCert, files) } diff --git a/packages/grpc/protos/file-transfer.proto b/packages/grpc/protos/file-transfer.proto index 730606e..3f9e38c 100644 --- a/packages/grpc/protos/file-transfer.proto +++ b/packages/grpc/protos/file-transfer.proto @@ -20,9 +20,10 @@ message FileNode { message StartTransferRequest { string port = 1; - string code = 2; - string ssl_cert = 3; - FileNode root = 4; + string ip = 2; + string code = 3; + string ssl_cert = 4; + FileNode root = 5; } message StartTransferResponse { diff --git a/packages/tauri-plugins/jarvis/Cargo.toml b/packages/tauri-plugins/jarvis/Cargo.toml index cbb2ae7..27f37d6 100644 --- a/packages/tauri-plugins/jarvis/Cargo.toml +++ b/packages/tauri-plugins/jarvis/Cargo.toml @@ -55,6 +55,7 @@ obfstr = { workspace = true } grpc = { workspace = true } futures-util = "0.3.31" rayon = { workspace = true } +local-ip-address = "0.6.3" [target.'cfg(target_os = "macos")'.dependencies] diff --git a/packages/tauri-plugins/jarvis/src/commands/file_transfer.rs b/packages/tauri-plugins/jarvis/src/commands/file_transfer.rs index fa454b5..c25d0cc 100644 --- a/packages/tauri-plugins/jarvis/src/commands/file_transfer.rs +++ b/packages/tauri-plugins/jarvis/src/commands/file_transfer.rs @@ -11,6 +11,7 @@ use grpc::file_transfer::{ file_transfer_client::FileTransferClient, FileNode, FileType, StartTransferRequest, StartTransferResponse, }; +use local_ip_address::local_ip; use std::{ collections::HashSet, path::{Path, PathBuf}, @@ -84,6 +85,7 @@ async fn download_file_node_recursively( stats: &mut TransferStats, progress_tx: mpsc::Sender, ) -> anyhow::Result<()> { + println!("download_file_node_recursively node: {:#?}", node); let mut stack = vec![(node.clone(), dir.to_path_buf())]; while let Some((current_node, current_dir)) = stack.pop() { @@ -96,7 +98,7 @@ async fn download_file_node_recursively( port = config.port, id = current_node.id ); - download_file( + match download_file( &url, &config.code, &download_path, @@ -104,7 +106,16 @@ async fn download_file_node_recursively( stats, progress_tx.clone(), ) - .await?; + .await + { + Ok(_) => (), + Err(e) => { + println!("download_file error: {:?}", e); + println!("download_file url: {:?}", url); + println!("download_file code: {:?}", config.code); + return Err(e); + } + }; } else if current_node.r#type == FileType::Directory as i32 { tokio::fs::create_dir_all(&download_path).await?; for child in current_node.children.iter() { @@ -134,12 +145,12 @@ pub async fn download_files( save_dir.display() )); } - + println!("download_files payload: {:?}", payload); let (progress_tx, mut progress_rx) = mpsc::channel::(100); let total_bytes = compute_total_size(&payload.root); let total_files = count_file_nodes(&payload.root); - let client = build_ssl_reqwest_client(None, Some(payload.ssl_cert.clone())) + let client = build_ssl_reqwest_client(Some(true), Some(payload.ssl_cert.clone())) .map_err(|e| e.to_string())?; if payload.root.filename.is_empty() { @@ -262,12 +273,14 @@ pub async fn local_net_send_file( .map_err(|err| err.to_string())?; let mut client = FileTransferClient::new(tls_channel); // Send the transfer request + let my_local_ip = local_ip().unwrap(); let response: tonic::Response = client .start_transfer(StartTransferRequest { port: port.to_string(), root: Some(root), code: uuid.clone(), ssl_cert: cert_pem, + ip: my_local_ip.to_string(), }) .await .map_err(|e| e.to_string())?; diff --git a/packages/tauri-plugins/jarvis/src/server/grpc/file_transfer.rs b/packages/tauri-plugins/jarvis/src/server/grpc/file_transfer.rs index 9dea259..5c144ee 100644 --- a/packages/tauri-plugins/jarvis/src/server/grpc/file_transfer.rs +++ b/packages/tauri-plugins/jarvis/src/server/grpc/file_transfer.rs @@ -32,19 +32,19 @@ impl FileTransfer for MyFileTransfer { request: Request, // Accept request of type StartTransferRequest ) -> Result, Status> { let reply = StartTransferResponse {}; - // let ip = request.remote_addr().unwrap().ip(); - let ip = "localhost"; - println!("start_transfer remote addr: {:?}", request.remote_addr()); let payload = request.into_inner(); println!("start_transfer payload: {:?}", payload); + let src_ip = payload.ip; + println!("src_ip: {:?}", src_ip); let root = if let Some(root) = payload.root { root } else { return Err(Status::invalid_argument("root is required")); }; + let total_bytes = compute_total_size(&root); let total_files = count_file_nodes(&root); - // get ip from request + self.app_handle .emit( "file-transfer-request", @@ -54,12 +54,13 @@ impl FileTransfer for MyFileTransfer { root, total_bytes, total_files, - ip: ip.to_string(), + ip: src_ip, ssl_cert: payload.ssl_cert, }, ) .map_err(|e| Status::internal(e.to_string()))?; - Ok(Response::new(reply)) // Send back our formatted greeting + + Ok(Response::new(reply)) } } @@ -257,8 +258,9 @@ mod test { .arg("f") .output() .unwrap() - .stdout - ).unwrap(); + .stdout, + ) + .unwrap(); let count2 = stdout.lines().count(); assert_eq!(count, count2); }