fix: implement aria2 polling to prevent UI from sticking on queued

This commit is contained in:
NimBold
2026-06-15 17:51:32 +03:30
parent 58f0f0dfb1
commit 601b04c4cb
2 changed files with 83 additions and 5 deletions
+3 -3
View File
@@ -577,7 +577,7 @@ fn build_client(payload: &DownloadPayload) -> Result<Client, String> {
builder.build().map_err(|error| error.to_string())
}
fn format_speed(bytes_per_second: f64) -> String {
pub(crate) fn format_speed(bytes_per_second: f64) -> String {
if bytes_per_second >= 1024.0 * 1024.0 {
format!("{:.1} MB/s", bytes_per_second / (1024.0 * 1024.0))
} else if bytes_per_second >= 1024.0 {
@@ -587,7 +587,7 @@ fn format_speed(bytes_per_second: f64) -> String {
}
}
fn format_size(bytes: f64) -> String {
pub(crate) fn format_size(bytes: f64) -> String {
if bytes >= 1024.0 * 1024.0 * 1024.0 {
format!("{:.2} GB", bytes / (1024.0 * 1024.0 * 1024.0))
} else if bytes >= 1024.0 * 1024.0 {
@@ -599,7 +599,7 @@ fn format_size(bytes: f64) -> String {
}
}
fn format_duration(seconds: f64) -> String {
pub(crate) fn format_duration(seconds: f64) -> String {
if seconds >= 3600.0 {
format!("{:.0}h {:.0}m", seconds / 3600.0, (seconds % 3600.0) / 60.0)
} else if seconds >= 60.0 {
+80 -2
View File
@@ -686,11 +686,20 @@ async fn start_download(
options
]);
rpc_call(state.aria2_port, &state.aria2_secret, "aria2.addUri", params)
let result = rpc_call(state.aria2_port, &state.aria2_secret, "aria2.addUri", params)
.await
.map(|_| ())
.map_err(|e| AppError::Internal(e))?;
let gid = result.as_str().unwrap_or("").to_string();
let port = state.aria2_port;
let secret = state.aria2_secret.clone();
let app_handle_clone = app_handle.clone();
let id_clone = id.clone();
tauri::async_runtime::spawn(async move {
poll_aria2(app_handle_clone, port, secret, id_clone, gid).await;
});
return Ok(());
}
state
@@ -1573,3 +1582,72 @@ async fn db_delete_queue(state: tauri::State<'_, crate::db::DbState>, id: String
let conn = state.conn.lock().await;
crate::db::delete_queue(&conn, &id).map_err(|e| e.to_string())
}
async fn poll_aria2(app_handle: tauri::AppHandle, port: u16, secret: String, id: String, gid: String) {
use tauri::Emitter;
let mut interval = tokio::time::interval(std::time::Duration::from_millis(1000));
loop {
interval.tick().await;
let params = serde_json::json!([gid, ["status", "totalLength", "completedLength", "downloadSpeed", "errorMessage"]]);
match rpc_call(port, &secret, "aria2.tellStatus", params).await {
Ok(status_info) => {
let status = status_info.get("status").and_then(|s| s.as_str()).unwrap_or("");
if status == "active" || status == "waiting" || status == "paused" {
let total_str = status_info.get("totalLength").and_then(|s| s.as_str()).unwrap_or("0");
let completed_str = status_info.get("completedLength").and_then(|s| s.as_str()).unwrap_or("0");
let speed_str = status_info.get("downloadSpeed").and_then(|s| s.as_str()).unwrap_or("0");
let total = total_str.parse::<u64>().unwrap_or(0);
let completed = completed_str.parse::<u64>().unwrap_or(0);
let speed_bytes = speed_str.parse::<f64>().unwrap_or(0.0);
let fraction = if total > 0 { completed as f64 / total as f64 } else { 0.0 };
let speed = crate::download::format_speed(speed_bytes);
let eta = if speed_bytes > 0.0 && total > completed {
crate::download::format_duration((total - completed) as f64 / speed_bytes)
} else {
"-".to_string()
};
let size = if total > 0 {
Some(crate::download::format_size(total as f64))
} else {
None
};
let _ = app_handle.emit("download-progress", serde_json::json!({
"id": id,
"fraction": fraction,
"speed": speed,
"eta": eta,
"size": size
}));
} else if status == "complete" {
let _ = app_handle.emit("download-complete", id);
break;
} else if status == "error" {
let err = status_info.get("errorMessage").and_then(|s| s.as_str()).unwrap_or("aria2 error").to_string();
let _ = app_handle.emit("download-failed", serde_json::json!({
"id": id,
"error": err
}));
break;
} else if status == "removed" {
let _ = app_handle.emit("download-failed", serde_json::json!({
"id": id,
"error": "Removed from aria2"
}));
break;
}
}
Err(e) => {
let _ = app_handle.emit("download-failed", serde_json::json!({
"id": id,
"error": format!("RPC error: {}", e)
}));
break;
}
}
}
}