[desktop] Use custom Tauri command for HTTP requests instead of http-client plugin
Replaced the http-client plugin, as it does not support keep-alive connections. Each request opened a new TCP connection to the service, which was inefficient. The new custom `send_tauri_http_request` command, exposed to the UI, uses an application-wide `reqwest::Client`, which supports idle (persistent) connections.
This commit is contained in:
113
desktop/tauri/src-tauri/Cargo.lock
generated
113
desktop/tauri/src-tauri/Cargo.lock
generated
@@ -1227,12 +1227,6 @@ version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010"
|
||||
|
||||
[[package]]
|
||||
name = "data-url"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a"
|
||||
|
||||
[[package]]
|
||||
name = "dataurl"
|
||||
version = "0.1.2"
|
||||
@@ -2026,10 +2020,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2039,11 +2031,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi 0.14.2+wasi-0.2.4",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2381,7 +2371,6 @@ dependencies = [
|
||||
"tokio",
|
||||
"tokio-rustls 0.26.2",
|
||||
"tower-service",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3988,7 +3977,6 @@ dependencies = [
|
||||
"tauri-build",
|
||||
"tauri-plugin-clipboard-manager",
|
||||
"tauri-plugin-dialog",
|
||||
"tauri-plugin-http",
|
||||
"tauri-plugin-log",
|
||||
"tauri-plugin-notification",
|
||||
"tauri-plugin-os",
|
||||
@@ -4158,60 +4146,6 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn"
|
||||
version = "0.11.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"cfg_aliases 0.2.1",
|
||||
"pin-project-lite",
|
||||
"quinn-proto",
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.25",
|
||||
"socket2 0.5.9",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-proto"
|
||||
version = "0.11.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"getrandom 0.3.2",
|
||||
"rand 0.9.0",
|
||||
"ring",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.25",
|
||||
"rustls-pki-types",
|
||||
"slab",
|
||||
"thiserror 2.0.12",
|
||||
"tinyvec",
|
||||
"tracing",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn-udp"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5"
|
||||
dependencies = [
|
||||
"cfg_aliases 0.2.1",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2 0.5.9",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
@@ -4465,10 +4399,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
"rustls 0.23.25",
|
||||
"rustls-pemfile",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
@@ -4476,7 +4407,6 @@ dependencies = [
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tokio-rustls 0.26.2",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
"tower-service",
|
||||
@@ -4485,7 +4415,6 @@ dependencies = [
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-streams",
|
||||
"web-sys",
|
||||
"webpki-roots",
|
||||
"windows-registry",
|
||||
]
|
||||
|
||||
@@ -4601,12 +4530,6 @@ version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
@@ -4676,7 +4599,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki 0.103.1",
|
||||
"subtle",
|
||||
@@ -4697,9 +4619,6 @@ name = "rustls-pki-types"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
|
||||
dependencies = [
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
@@ -5561,28 +5480,6 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-http"
|
||||
version = "2.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "696ef548befeee6c6c17b80ef73e7c41205b6c2204e87ef78ccc231212389a5c"
|
||||
dependencies = [
|
||||
"data-url",
|
||||
"http",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"tauri-plugin-fs",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"url",
|
||||
"urlpattern",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-log"
|
||||
version = "2.3.1"
|
||||
@@ -6682,16 +6579,6 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-time"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webkit2gtk"
|
||||
version = "2.0.1"
|
||||
|
||||
@@ -25,7 +25,6 @@ tauri-plugin-single-instance = "2.2.1"
|
||||
tauri-plugin-notification = "2.2.1"
|
||||
tauri-plugin-log = "2.2.1"
|
||||
tauri-plugin-window-state = "2.2.1"
|
||||
tauri-plugin-http = "2"
|
||||
tauri-plugin-websocket = "2"
|
||||
|
||||
clap_lex = "0.7.2"
|
||||
@@ -49,7 +48,7 @@ http = "1.0.0"
|
||||
url = "2.5.0"
|
||||
thiserror = "1.0"
|
||||
log = "0.4.21"
|
||||
reqwest = { version = "0.12" }
|
||||
reqwest = { version = "0.12", features = ["cookies", "json"] }
|
||||
|
||||
rfd = { version = "*", default-features = false, features = [ "tokio", "gtk3", "common-controls-v6" ] }
|
||||
open = "5.1.3"
|
||||
|
||||
@@ -33,20 +33,7 @@
|
||||
"window-state:allow-save-window-state",
|
||||
"window-state:allow-restore-state",
|
||||
"clipboard-manager:allow-read-text",
|
||||
"clipboard-manager:allow-write-text",
|
||||
{
|
||||
"identifier": "http:default",
|
||||
"allow": [
|
||||
{
|
||||
"url": "http://127.0.0.1:817/**"
|
||||
},
|
||||
{
|
||||
"url": "http://localhost:817/**"
|
||||
}
|
||||
]
|
||||
},
|
||||
"websocket:default",
|
||||
"http:default",
|
||||
"clipboard-manager:allow-write-text",
|
||||
"websocket:default"
|
||||
]
|
||||
}
|
||||
1
desktop/tauri/src-tauri/src/commands/mod.rs
Normal file
1
desktop/tauri/src-tauri/src/commands/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod tauri_http;
|
||||
75
desktop/tauri/src-tauri/src/commands/tauri_http.rs
Normal file
75
desktop/tauri/src-tauri/src/commands/tauri_http.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
use tauri::State;
|
||||
use reqwest::{Client, Method};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Creates and configures a shared HTTP client for application-wide use.
|
||||
///
|
||||
/// Returns a reqwest Client configured with:
|
||||
/// - Connection pooling
|
||||
/// - Persistent cookie store
|
||||
///
|
||||
/// Client can be accessed from UI through the exposed Tauri command `send_tauri_http_request(...)`
|
||||
/// Such requests execute directly from the Tauri app binary, not from the WebView process
|
||||
pub fn create_http_client() -> Client {
|
||||
Client::builder()
|
||||
// Maximum idle connections per host
|
||||
.pool_max_idle_per_host(10)
|
||||
// Enable cookie support
|
||||
.cookie_store(true)
|
||||
.user_agent("Portmaster UI")
|
||||
.build()
|
||||
.expect("failed to build HTTP client")
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct HttpRequestOptions {
|
||||
method: String,
|
||||
headers: Vec<(String, String)>,
|
||||
body: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct HttpResponse {
|
||||
status: u16,
|
||||
status_text: String,
|
||||
headers: Vec<(String, String)>,
|
||||
body: Vec<u8>,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn send_tauri_http_request(
|
||||
client: State<'_, Client>,
|
||||
url: String,
|
||||
opts: HttpRequestOptions
|
||||
) -> Result<HttpResponse, String> {
|
||||
//println!("URL: {}", url);
|
||||
|
||||
// Build the request
|
||||
let mut req = client
|
||||
.request(Method::from_bytes(opts.method.as_bytes()).map_err(|e| e.to_string())?, &url);
|
||||
|
||||
// Apply headers
|
||||
for (k, v) in opts.headers {
|
||||
req = req.header(&k, &v);
|
||||
}
|
||||
|
||||
// Attach body if present
|
||||
if let Some(body) = opts.body {
|
||||
req = req.body(body);
|
||||
}
|
||||
|
||||
// Send and await the response
|
||||
let resp = req.send().await.map_err(|e| e.to_string())?;
|
||||
|
||||
// Read status, headers, and body
|
||||
let status = resp.status().as_u16();
|
||||
let status_text = resp.status().canonical_reason().unwrap_or("").to_string();
|
||||
let headers = resp
|
||||
.headers()
|
||||
.iter()
|
||||
.map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string()))
|
||||
.collect();
|
||||
let body = resp.bytes().await.map_err(|e| e.to_string())?.to_vec();
|
||||
|
||||
Ok(HttpResponse { status, status_text, headers, body })
|
||||
}
|
||||
@@ -18,6 +18,7 @@ mod config;
|
||||
mod portmaster;
|
||||
mod traymenu;
|
||||
mod window;
|
||||
mod commands;
|
||||
|
||||
use log::{debug, error, info};
|
||||
use portmaster::PortmasterExt;
|
||||
@@ -145,9 +146,16 @@ fn main() {
|
||||
tauri_plugin_log::Target::new(tauri_plugin_log::TargetKind::Stdout)
|
||||
};
|
||||
|
||||
// Create a single HTTP client that:
|
||||
// - Pools and reuses connections for better performance
|
||||
// - Is exposed to UI through 'send_tauri_http_request()' command
|
||||
// - Such requests execute directly from the Tauri app binary, not from the WebView process
|
||||
let http_client = commands::tauri_http::create_http_client();
|
||||
|
||||
let app = tauri::Builder::default()
|
||||
// make HTTP client accessible in commands ('send_tauri_http_request()')
|
||||
.manage(http_client)
|
||||
.plugin(tauri_plugin_websocket::init())
|
||||
.plugin(tauri_plugin_http::init())
|
||||
// Shell plugin for open_external support
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
// Initialize Logging plugin.
|
||||
@@ -181,7 +189,8 @@ fn main() {
|
||||
portmaster::commands::get_state,
|
||||
portmaster::commands::set_state,
|
||||
portmaster::commands::should_show,
|
||||
portmaster::commands::should_handle_prompts
|
||||
portmaster::commands::should_handle_prompts,
|
||||
commands::tauri_http::send_tauri_http_request,
|
||||
])
|
||||
// Setup the app an any listeners
|
||||
.setup(move |app| {
|
||||
|
||||
Reference in New Issue
Block a user