细节调整及优化(26.8.3)
This commit is contained in:
@@ -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 存储,避免下载过程中反复锁 settings;save_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,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user