Skip to main content

ybd_core/
progress.rs

1//! 下载进度条与多任务进度管理模块
2//!
3//! 基于 `indicatif` 实现单任务和多任务并发下载进度可视化。
4
5use std::{collections::HashMap, time::Duration};
6
7use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
8
9pub struct DownloadProgress {
10        pub id: String,
11        pub pb: ProgressBar,
12}
13
14impl DownloadProgress {
15        pub fn new(
16                id: String,
17                total_size: u64,
18        ) -> Self {
19                let pb = ProgressBar::new(total_size);
20                pb.set_style(
21                        ProgressStyle::with_template(
22                                "{spinner:.green} [{wide_bar:.cyan/dim}] {bytes}/{total_bytes} ({eta})",
23                        )
24                        .unwrap()
25                        .progress_chars("█▓▒░  ")
26                );
27                Self { id, pb }
28        }
29
30        pub fn update(
31                &mut self,
32                inc: u64,
33        ) {
34                if self.pb.position() + inc >= self.pb.length().unwrap_or(0) {
35                        self.pb.inc(inc);
36                        self.pb.finish();
37                }
38                self.pb.inc(inc);
39        }
40}
41
42pub struct DownloadMutiProgess {
43        progress_bars: HashMap<String, ProgressBar>,
44        last_progress_bar: ProgressBar,
45        multi_progress: MultiProgress,
46}
47
48impl DownloadMutiProgess {
49        /// 这里total_number限定总进度条的上限,而不是取progres_bars的长度,
50        /// 处于美观需要,不会在add方法里面动态增长进度条上限
51        ///
52        /// * `progres_bars`: 初始进度条,一般是空向量
53        /// * `total_number`: 进度条上限
54        pub fn new(
55                progres_bars: Vec<DownloadProgress>,
56                total_number: u64,
57        ) -> Self {
58                let mut hm = HashMap::new();
59                let mp = MultiProgress::new();
60
61                // 总进度条先加,保证在最底部
62                let last_progress_bar = mp.add(ProgressBar::new(total_number));
63                last_progress_bar.set_style(
64                        ProgressStyle::with_template("总进度: [{bar:40.cyan/blue}] {pos}/{len} 个")
65                                .unwrap()
66                                .progress_chars("=>-"),
67                );
68                last_progress_bar.enable_steady_tick(Duration::from_millis(80));
69
70                // 初始传入的进度条都 insert_before
71                for v in progres_bars {
72                        let pb = mp.insert_before(&last_progress_bar, v.pb);
73                        hm.insert(v.id, pb);
74                }
75
76                Self {
77                        progress_bars: hm,
78                        last_progress_bar,
79                        multi_progress: mp,
80                }
81        }
82
83        pub fn add(
84                &mut self,
85                progress: DownloadProgress,
86        ) {
87                let pb = self
88                        .multi_progress
89                        .insert_before(&self.last_progress_bar, progress.pb);
90                self.progress_bars.insert(progress.id, pb);
91        }
92
93        pub fn update(
94                &mut self,
95                id: &str,
96                inc_len: u64,
97        ) {
98                let v = self.progress_bars.get(id);
99                if let Some(progress) = v {
100                        if progress.position() + inc_len >= progress.length().unwrap_or(0) {
101                                progress.inc(inc_len);
102                                progress.finish_and_clear();
103                                self.last_progress_bar.inc(1);
104                                return;
105                        }
106                        progress.inc(inc_len);
107                }
108        }
109
110        pub fn inc_total(&mut self) {
111                self.last_progress_bar.inc(1);
112        }
113
114        pub fn finish(&mut self) {
115                self.last_progress_bar.finish();
116        }
117}