bug修复调整

This commit is contained in:
zhongluofeng
2026-08-31 18:05:27 +08:00
parent 28e0c4664a
commit 6b9f71da08
35 changed files with 1004 additions and 296 deletions
+82 -8
View File
@@ -663,6 +663,67 @@ impl DownloadEngine {
}
}
/// BT 任务重新入会:句柄缺失(元数据未解析完/句柄被移除)时,重新加入会话以取回句柄。
/// librqbit 对已加入的种子返回 AlreadyManaged(复用现有句柄,已下载片段保留),
/// 因此对暂停→继续、错误→继续等场景都幂等、安全。
async fn reenter_bt(&self, id: &str, url: &str, dir: &str) -> Result<(), String> {
let added = tokio::time::timeout(
std::time::Duration::from_secs(crate::download_engine::torrent::INSPECT_TIMEOUT_SECS),
self.inner.torrent.add_async(url, dir),
).await;
let (_, handle) = match added {
Ok(Ok(v)) => v,
Ok(Err(e)) => return Err(e),
Err(_) => return Err("解析磁力元数据超时:未能从 DHT/Tracker 获取种子信息".to_string()),
};
// 存回句柄(句柄存在则更新,缺失则新建)
{
let mut handles = self.inner.handles.lock().unwrap_or_else(|e| e.into_inner());
match handles.get_mut(id) {
Some(h) => h.bt = Some(handle.clone()),
None => {
handles.insert(
id.to_string(),
TaskHandle {
gen: self.inner.next_gen.fetch_add(1, Ordering::SeqCst) + 1,
cancel: Arc::new(AtomicBool::new(false)),
progress: Vec::new(),
join: Mutex::new(None),
bt: Some(handle.clone()),
},
);
}
}
}
// 等待元数据就绪(本地 .torrent 秒回;磁力依赖网络,带超时)
if let Err(e) = self.inner.torrent.wait_initialized(&handle).await {
return Err(e);
}
// 刷新结构化任务元数据(filename / infohash / 文件列表 / 大小)
match self.inner.torrent.inspect(url).await {
Ok(info) => {
let mut tasks = self.inner.tasks.lock().unwrap_or_else(|e| e.into_inner());
if let Some(t) = tasks.get_mut(id) {
t.filename = info.name.clone();
t.info_hash = Some(info.info_hash.clone());
t.bt_files = info.files.clone();
t.total_size = info.total_size;
t.bt_metadata_ready = true;
t.error = None;
// 复位为 Queuedstart_download 只在 Queued 下继续推进(首调时已置 Active)
if matches!(t.status, TaskStatus::Active | TaskStatus::Error) {
t.status = TaskStatus::Queued;
}
}
}
Err(e) => return Err(e),
}
self.persist_now();
Ok(())
}
/// BT 元数据解析失败:任务置为 Error 并通知前端刷新
fn fail_bt_resolve(engine: &DownloadEngine, id: &str, error: String) {
{
@@ -1245,15 +1306,28 @@ impl DownloadEngine {
// ===== BitTorrent 下载分支 =====
if is_bt {
let Some(bt) = existing_bt else {
// 无 BT 句柄(异常):标记 Error
{
let mut tasks = self.inner.tasks.lock().unwrap_or_else(|e| e.into_inner());
if let Some(task) = tasks.get_mut(&id) {
task.status = TaskStatus::Error;
task.error = Some("BitTorrent 句柄缺失".to_string());
// 无 BT 句柄:常见于元数据尚未解析完就点了"暂停/继续",或句柄已被移除。
// 不能直接报"句柄缺失"(否则此类任务点"继续"会立即失败),改为后台重新加入
// 会话(如已加入则复用已有句柄,已下载片段保留),元数据就绪后再进入下载。
let engine2 = self.clone();
let id2 = id.clone();
let url2 = task.url.clone();
let dir2 = task.dir.clone();
tauri::async_runtime::spawn(async move {
if let Err(e) = engine2.reenter_bt(&id2, &url2, &dir2).await {
crate::logger::log_error("download", &format!("BT 任务重入会话失败: {}", e));
let mut tasks = engine2.inner.tasks.lock().unwrap_or_else(|e| e.into_inner());
if let Some(t) = tasks.get_mut(&id2) {
if t.status == TaskStatus::Active || t.status == TaskStatus::Queued {
t.status = TaskStatus::Error;
t.error = Some(e);
}
}
engine2.persist_now();
return;
}
}
self.persist_now();
engine2.start_download(id2);
});
return;
};