[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:
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