Skip to main content

fast_down_gui/core/
start.rs

1use crate::{
2    core::{App, download},
3    persist::{self, DatabaseEntry},
4    ui::{DownloadConfig, EntryData, Status},
5    utils::{ForceSendExt, LogErr},
6};
7use fast_down_ffi::FileId;
8use slint::{SharedString, ToSharedString, VecModel};
9use std::{path::PathBuf, time::Duration};
10use tokio_util::sync::CancellationToken;
11use tracing::{error, info};
12use url::Url;
13
14/// 返回 false 意味任务没有成功添加到 task_set 中
15pub fn start_entry(app: &App, entry: &EntryData, list: &VecModel<EntryData>) -> bool {
16    if matches!(entry.status, Status::Running | Status::Waiting) {
17        return false;
18    }
19    let gid = entry.gid;
20    let Some(db_entry) = app.db.inner.data.get(&gid).map(|e| e.clone()) else {
21        return false;
22    };
23    let url = db_entry.url.clone();
24    let config = db_entry.config.to_ui_download_config();
25    if db_entry.status == persist::Status::Completed {
26        start_new_entry(app, url, &config, list);
27        return false;
28    }
29    let app_c = app.clone();
30    let cancel_token = CancellationToken::new();
31    let token = cancel_token.clone();
32    let fut = async move {
33        app_c.update_ui_row(gid, move |_, data| data.error = SharedString::new());
34        let handler = app_c.create_download_handler(gid);
35        match download(url, &config, token, Some(db_entry), handler).await {
36            Ok(()) => info!(gid = gid, "任务下载完成"),
37            Err(e) => {
38                error!(gid = gid, err = ?e, "下载任务出错");
39                app_c.db.update_status(gid, persist::Status::Error);
40                app_c.update_ui_row(gid, move |_, data| {
41                    data.status = Status::Error;
42                    data.error = e.to_shared_string();
43                });
44            }
45        }
46    }
47    .force_send();
48    app.task_set.add_task(gid, cancel_token, fut);
49    true
50}
51
52pub fn start_new_entry(
53    app: &App,
54    url: Url,
55    config: &DownloadConfig,
56    list_model: &VecModel<EntryData>,
57) {
58    let gid = app.db.next_gid();
59    let entry = DatabaseEntry {
60        file_name: url.to_string(),
61        file_path: PathBuf::new(),
62        file_size: 0,
63        file_id: FileId::default(),
64        progress: Vec::new(),
65        elapsed: Duration::ZERO,
66        url: url.clone(),
67        config: config.into(),
68        status: persist::Status::Paused,
69    };
70    let mut ui_entry = entry.to_entry_data(gid);
71    ui_entry.status = Status::Waiting;
72    list_model.push(ui_entry);
73    let _ = app.db.init_entry(gid, entry).log_err("数据库插入条目失败");
74
75    let app_c = app.clone();
76    let cancel_token = CancellationToken::new();
77    let token = cancel_token.clone();
78    let config = config.clone();
79
80    let fut = async move {
81        let handler = app_c.create_download_handler(gid);
82        match download(url, &config, token, None, handler).await {
83            Ok(()) => info!(gid = gid, "任务下载完成"),
84            Err(e) => {
85                error!(gid = gid, err = ?e, "下载任务出错");
86                app_c.db.update_status(gid, persist::Status::Error);
87                app_c.update_ui_row(gid, move |_, data| {
88                    data.status = Status::Error;
89                    data.error = e.to_shared_string();
90                });
91            }
92        }
93    }
94    .force_send();
95    app.task_set.add_task(gid, cancel_token, fut);
96}