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