refactor: rootless wayfern launch and exponential backoff for downloads

This commit is contained in:
zhom
2026-03-24 01:49:34 +04:00
parent 084e63eb1e
commit aa2e9e2528
2 changed files with 56 additions and 32 deletions
+40 -29
View File
@@ -323,9 +323,10 @@ impl Downloader {
existing_size = meta.len(); existing_size = meta.len();
} }
// Build request, add Range only if we have bytes. If the server responds with 416 (Range Not // Build request with retry logic for transient network errors.
// Satisfiable), delete the partial file and retry once without the Range header. let max_retries = 3u32;
let response = { let mut response: Option<reqwest::Response> = None;
for attempt in 0..=max_retries {
let mut request = self let mut request = self
.client .client
.get(&download_url) .get(&download_url)
@@ -338,33 +339,43 @@ impl Downloader {
request = request.header("Range", format!("bytes={existing_size}-")); request = request.header("Range", format!("bytes={existing_size}-"));
} }
log::info!("Sending download request..."); log::info!("Sending download request (attempt {})...", attempt + 1);
let first = request.send().await?; match request.send().await {
log::info!( Ok(resp) => {
"Download response received: status={}, content-length={:?}", log::info!(
first.status(), "Download response received: status={}, content-length={:?}",
first.content_length() resp.status(),
); resp.content_length()
);
if first.status().as_u16() == 416 && existing_size > 0 { if resp.status().as_u16() == 416 && existing_size > 0 {
// Partial file on disk is not acceptable to the server — remove it and retry from scratch let _ = std::fs::remove_file(&file_path);
let _ = std::fs::remove_file(&file_path); existing_size = 0;
existing_size = 0; log::warn!("Download returned 416, retrying without Range header");
continue;
let retry = self }
.client response = Some(resp);
.get(&download_url) break;
.header( }
"User-Agent", Err(e) => {
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36", let is_retryable = e.is_connect() || e.is_timeout() || e.is_request();
) if is_retryable && attempt < max_retries {
.send() let delay = 2u64.pow(attempt);
.await?; log::warn!(
retry "Download attempt {} failed ({}), retrying in {}s...",
} else { attempt + 1,
first e,
delay
);
tokio::time::sleep(std::time::Duration::from_secs(delay)).await;
} else {
return Err(format!("Download failed after {} attempts: {}", attempt + 1, e).into());
}
}
} }
}; }
let response = response.ok_or_else(|| -> Box<dyn std::error::Error + Send + Sync> {
"Download failed: no response received".into()
})?;
// Check if the response is successful (200 OK or 206 Partial Content) // Check if the response is successful (200 OK or 206 Partial Content)
if !(response.status().is_success() || response.status().as_u16() == 206) { if !(response.status().is_success() || response.status().as_u16() == 206) {
+16 -3
View File
@@ -233,9 +233,15 @@ impl WayfernManager {
.arg("--disable-background-mode") .arg("--disable-background-mode")
.arg("--use-mock-keychain") .arg("--use-mock-keychain")
.arg("--password-store=basic") .arg("--password-store=basic")
.arg("--disable-features=DialMediaRouteProvider") .arg("--disable-features=DialMediaRouteProvider");
.stdout(Stdio::null())
.stderr(Stdio::null()); #[cfg(target_os = "linux")]
cmd
.arg("--no-sandbox")
.arg("--disable-setuid-sandbox")
.arg("--disable-dev-shm-usage");
cmd.stdout(Stdio::null()).stderr(Stdio::null());
let child = cmd.spawn()?; let child = cmd.spawn()?;
let child_id = child.id(); let child_id = child.id();
@@ -549,6 +555,13 @@ impl WayfernManager {
"--password-store=basic".to_string(), "--password-store=basic".to_string(),
]; ];
#[cfg(target_os = "linux")]
{
args.push("--no-sandbox".to_string());
args.push("--disable-setuid-sandbox".to_string());
args.push("--disable-dev-shm-usage".to_string());
}
if let Some(proxy) = proxy_url { if let Some(proxy) = proxy_url {
args.push(format!("--proxy-server={proxy}")); args.push(format!("--proxy-server={proxy}"));
} }