细节调整及优化(26.8.3)

This commit is contained in:
zhongluofeng
2026-08-21 17:25:47 +08:00
parent 0a19b4b38a
commit 4dd60f42a1
72 changed files with 4779 additions and 1395 deletions
+49 -9
View File
@@ -64,6 +64,8 @@ pub struct ProgressPayload {
pub total_size: u64,
pub speed: u64,
pub status: TaskStatus,
/// 每个分段的已下载字节(与任务 segments 一一对应,供前端详情弹窗实时展示)
pub segments: Vec<u64>,
}
/// 完成事件载荷(发给前端 download-complete 事件)
@@ -107,6 +109,9 @@ struct EngineInner {
global_limiter: Arc<RateLimiter>,
/// HTTP 下载器
http: HttpDownloader,
/// 下载是否使用代理(true=尊重系统代理,false=强制直连)
/// 独立于 settings 存储,避免下载过程中反复锁 settingssave_settings 时同步更新
use_proxy: AtomicBool,
/// Tauri 应用句柄(用于发事件)
app_handle: AppHandle,
/// 引擎是否已启动
@@ -144,6 +149,8 @@ impl DownloadEngine {
0
};
let global_limiter = Arc::new(RateLimiter::new(global_limit));
// 在 settings 移入 Mutex 前读取代理开关
let use_proxy = settings.use_proxy;
let engine = Self {
inner: Arc::new(EngineInner {
@@ -153,6 +160,7 @@ impl DownloadEngine {
settings: Mutex::new(settings),
global_limiter,
http: HttpDownloader::new(),
use_proxy: AtomicBool::new(use_proxy),
app_handle,
started: AtomicBool::new(false),
next_gen: AtomicU64::new(0),
@@ -188,7 +196,8 @@ impl DownloadEngine {
dir: Option<&str>,
headers: &HashMap<String, String>,
) -> (Result<ProbeResult, String>, DuplicateKind, Option<ExistingTaskInfo>) {
let probe = self.inner.http.probe(url, headers).await;
let use_proxy = self.inner.use_proxy.load(Ordering::SeqCst);
let probe = self.inner.http.probe(url, headers, use_proxy).await;
let settings = self.inner.settings.lock().unwrap_or_else(|e| e.into_inner()).clone();
let task_dir = dir.map(|d| d.to_string()).unwrap_or_else(|| settings.download_dir.clone());
@@ -250,11 +259,30 @@ impl DownloadEngine {
}
/// 生成不冲突的文件名(同名时追加 (1)、(2)...)
/// 冲突来源:磁盘已有同名最终文件、已存在同名临时文件(其他任务正在下载该名)、
/// 以及任务列表中已有任务占用同名(即使最终文件尚未落盘,避免共用同一 .thingdl 临时文件)
fn generate_unique_filename(&self, dir: &str, filename: &str) -> String {
let path = PathBuf::from(dir).join(filename);
if !path.exists() {
// 任务列表中已占用的文件名(同一目录下)
let taken: std::collections::HashSet<String> = {
let tasks = self.inner.tasks.lock().unwrap_or_else(|e| e.into_inner());
tasks
.values()
.filter(|t| t.dir == dir)
.map(|t| t.filename.clone())
.collect()
};
// 磁盘最终文件 / 临时文件 / 任务占用,三者任一冲突即视为被占用
let used = |name: &str| {
taken.contains(name)
|| PathBuf::from(dir).join(name).exists()
|| PathBuf::from(dir).join(format!("{}.thingdl", name)).exists()
};
if !used(filename) {
return filename.to_string();
}
let path = PathBuf::from(dir).join(filename);
let stem = path.file_stem().and_then(|s| s.to_str()).unwrap_or("download");
let ext = path.extension().and_then(|s| s.to_str());
for i in 1..1000 {
@@ -262,8 +290,7 @@ impl DownloadEngine {
Some(e) => format!("{} ({}).{}", stem, i, e),
None => format!("{} ({})", stem, i),
};
let new_path = PathBuf::from(dir).join(&new_name);
if !new_path.exists() {
if !used(&new_name) {
return new_name;
}
}
@@ -285,7 +312,8 @@ impl DownloadEngine {
auto_rename: bool,
) -> Result<String, String> {
// 探测资源信息
let probe = self.inner.http.probe(&url, &headers).await;
let use_proxy = self.inner.use_proxy.load(Ordering::SeqCst);
let probe = self.inner.http.probe(&url, &headers, use_proxy).await;
let settings = self.inner.settings.lock().unwrap_or_else(|e| e.into_inner()).clone();
let task_dir = dir.unwrap_or_else(|| settings.download_dir.clone());
@@ -419,8 +447,8 @@ impl DownloadEngine {
if task.status != TaskStatus::Paused && task.status != TaskStatus::Error {
return Err("任务不在可恢复状态".to_string());
}
// 如果不支持断点续传,从头开始
if !task.supports_resume {
// 如果不支持断点续传,或文件大小未知(无法定位续传起点,需从头下载),从头开始
if !task.supports_resume || task.total_size == 0 {
task.completed_size = 0;
for seg in &mut task.segments {
seg.completed = 0;
@@ -491,6 +519,11 @@ impl DownloadEngine {
};
self.inner.global_limiter.set_limit(new_limit);
// 同步代理开关(新任务/探测立即生效,正在下载的任务不受影响)
self.inner
.use_proxy
.store(settings.use_proxy, Ordering::SeqCst);
{
let mut s = self.inner.settings.lock().unwrap_or_else(|e| e.into_inner());
*s = settings;
@@ -613,11 +646,12 @@ impl DownloadEngine {
let temp_file_path = task.temp_file_path();
let final_file_path = task.file_path();
let http = self.inner.http.clone();
let use_proxy = self.inner.use_proxy.load(Ordering::SeqCst);
let join = tauri::async_runtime::spawn(async move {
let my_gen = gen;
let result = http
.download(&url, &headers, &segments, &temp_file_path, cancel_clone, &progress_clone, limiter)
.download(&url, &headers, &segments, &temp_file_path, cancel_clone, &progress_clone, limiter, use_proxy)
.await;
// 代际守卫:仅最新代际的任务能更新状态 / 移除句柄 / 发完成事件。
@@ -748,6 +782,11 @@ impl DownloadEngine {
.iter()
.map(|p| p.load(Ordering::Relaxed))
.sum();
// 各分段实时进度(供前端详情弹窗分段条展示)
let segment_completed: Vec<u64> = progress_monitor
.iter()
.map(|p| p.load(Ordering::Relaxed))
.collect();
// 计算速度
let now = Instant::now();
@@ -788,6 +827,7 @@ impl DownloadEngine {
total_size,
speed,
status: live_status,
segments: segment_completed,
},
);
}