bug修复调整
This commit is contained in:
@@ -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;
|
||||
// 复位为 Queued:start_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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user