mirror of
https://github.com/nimbold/Firelink.git
synced 2026-07-26 12:08:27 +00:00
fix: resolve deadlock, redownload failure, and UI issues
- Fix re-entrant deadlock in `legacy_download_queue_paths` by scoping DB lock - Ensure `release_registered_id` runs in `remove_download` even if cleanup fails - Add fallback to `std::fs::remove_file` if `trash::delete` fails - Ignore 'cannot be paused now' error in `detach_download_for_reconfigure` - Apply `break-all` and `whitespace-pre-wrap` to Toast messages to prevent UI overflow
This commit is contained in:
@@ -144,13 +144,15 @@ fn load_records(app_handle: &tauri::AppHandle) -> Result<Vec<DownloadOwnershipRe
|
||||
fn legacy_download_queue_paths(app_handle: &tauri::AppHandle) -> Result<Vec<PathBuf>, String> {
|
||||
let settings = crate::settings::load_settings(app_handle).ok();
|
||||
|
||||
let database = app_handle.state::<crate::db::DbState>();
|
||||
let connection = database.lock()?;
|
||||
let downloads = crate::db::load_downloads(&connection)?
|
||||
.into_iter()
|
||||
.map(|value| serde_json::from_str::<crate::ipc::DownloadItem>(&value))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|error| format!("Invalid download queue ownership data: {error}"))?;
|
||||
let downloads = {
|
||||
let database = app_handle.state::<crate::db::DbState>();
|
||||
let connection = database.lock()?;
|
||||
crate::db::load_downloads(&connection)?
|
||||
.into_iter()
|
||||
.map(|value| serde_json::from_str::<crate::ipc::DownloadItem>(&value))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|error| format!("Invalid download queue ownership data: {error}"))?
|
||||
};
|
||||
|
||||
let mut paths = Vec::new();
|
||||
for download in downloads {
|
||||
|
||||
+25
-10
@@ -2869,15 +2869,19 @@ async fn remove_download(
|
||||
crate::ipc::DownloadStateEvent::new(id.clone(), crate::ipc::DownloadStatus::Paused),
|
||||
);
|
||||
|
||||
if delete_assets {
|
||||
if let Some(path) = primary_path.as_deref() {
|
||||
remove_download_assets(path, &app_handle).await?;
|
||||
let cleanup_result = (|| async {
|
||||
if delete_assets {
|
||||
if let Some(path) = primary_path.as_deref() {
|
||||
remove_download_assets(path, &app_handle).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
crate::download_ownership::remove(&app_handle, &id)?;
|
||||
Ok::<(), String>(())
|
||||
})()
|
||||
.await;
|
||||
|
||||
crate::download_ownership::remove(&app_handle, &id)?;
|
||||
state.queue_manager.release_registered_id(&id).await;
|
||||
Ok(())
|
||||
cleanup_result
|
||||
}
|
||||
|
||||
async fn remove_download_assets(
|
||||
@@ -2889,8 +2893,12 @@ async fn remove_download_assets(
|
||||
}
|
||||
|
||||
if primary.exists() {
|
||||
trash::delete(primary)
|
||||
.map_err(|error| format!("failed to move downloaded file to Trash: {error}"))?;
|
||||
if let Err(e) = trash::delete(primary) {
|
||||
log::warn!("failed to move downloaded file to Trash, attempting hard delete: {}", e);
|
||||
if let Err(hard_err) = std::fs::remove_file(primary) {
|
||||
return Err(format!("failed to move downloaded file to Trash ({e}) and hard delete failed ({hard_err})"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for suffix in [".aria2", ".part", ".ytdl"] {
|
||||
@@ -2923,13 +2931,20 @@ async fn detach_download_for_reconfigure(
|
||||
|
||||
if let Some(gid) = gid.as_deref().filter(|gid| !gid.starts_with("native:")) {
|
||||
let removal_result = async {
|
||||
rpc_call(
|
||||
let pause_res = rpc_call(
|
||||
state.aria2_port.load(std::sync::atomic::Ordering::Relaxed),
|
||||
&state.aria2_secret,
|
||||
"aria2.forcePause",
|
||||
serde_json::json!([gid]),
|
||||
)
|
||||
.await?;
|
||||
.await;
|
||||
|
||||
if let Err(e) = pause_res {
|
||||
if !e.contains("cannot be paused now") {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
||||
wait_for_aria2_stopped(
|
||||
state.aria2_port.load(std::sync::atomic::Ordering::Relaxed),
|
||||
&state.aria2_secret,
|
||||
|
||||
@@ -162,7 +162,7 @@ const ToastItem: React.FC<{ toast: ToastState; removeToast: (id: string) => void
|
||||
onBlur={() => setIsHovered(false)}
|
||||
>
|
||||
<div className="mt-0.5 shrink-0">{Icon}</div>
|
||||
<div className="font-semibold flex-1 tracking-tight">{toast.message}</div>
|
||||
<div className="font-semibold flex-1 tracking-tight break-all whitespace-pre-wrap">{toast.message}</div>
|
||||
<button
|
||||
onClick={() => removeToast(toast.id)}
|
||||
className="shrink-0 ml-2 mt-0.5 opacity-60 hover:opacity-100 hover:bg-black/5 dark:hover:bg-white/10 p-1 rounded-full transition-all active:scale-90"
|
||||
|
||||
Reference in New Issue
Block a user