1use futures::future::join_all;
2use indicatif::ProgressBar;
3use indicatif::{MultiProgress, ProgressStyle};
4use std::fs::create_dir_all;
5use std::sync::Arc;
6use std::time::Instant;
7use tokio::task::JoinHandle;
8
9use crate::download::*;
10use crate::fetch::*;
11
12struct TopicHandler<'a> {
13 topic: &'a str,
14 download_manager: DLManager,
15}
16
17impl<'a> TopicHandler<'a> {
18 pub async fn download_topic(&mut self, dir: String) -> u8 {
19 let nsamples = self.download_manager.target_size;
20
21 let dir = format!("{}/{}", dir, self.topic);
23
24 let batch = Fetcher::query_api(self.topic, nsamples).await;
25 let total = self.download_manager.download_batch(batch, &dir).await;
26 total
27 }
28}
29
30pub struct TinyDataClient {
31 multi_progress_bar: MultiProgress,
32}
33
34impl TinyDataClient {
35 pub fn new() -> Self {
36 Self {
37 multi_progress_bar: MultiProgress::new(),
38 }
39 }
40
41 pub async fn run(&self, topics: Vec<String>, nsamples: usize, dir: String) {
42 for topic in &topics {
44 let dir = format!("{}/{}", dir, topic);
45 create_dir_all(&dir).expect("failed to create directory");
46 }
47
48 let dir = Arc::new(dir);
50 let topics_len = topics.len();
51
52 let futures: Vec<JoinHandle<u8>> = topics
53 .into_iter()
54 .map(|topic| {
55 let dir = Arc::clone(&dir);
56 let mut pb = self
57 .multi_progress_bar
58 .add(ProgressBar::new(nsamples as u64));
59
60 stylize_pb(&mut pb, &topic);
62
63 tokio::spawn(async move {
64 let download_manager = DLManager::new(nsamples, pb);
65
66 let mut topic_handler = TopicHandler {
67 topic: &topic,
68 download_manager,
69 };
70 topic_handler.download_topic(dir.to_string()).await
71 })
72 })
73 .collect();
74
75 let now = Instant::now();
77 let total = join_all(futures).await;
78 let elapsed = now.elapsed();
79
80 let total: u8 = total.into_iter().map(|res| res.unwrap()).sum();
81
82 println!(
83 "{}/{} files saved successfully to `./{}` in {}s 📦",
84 total,
85 nsamples * topics_len,
86 dir,
87 elapsed.as_secs(),
88 );
89 }
90}
91
92fn stylize_pb(pb: &mut ProgressBar, name: &str) {
93 let default = "{msg} {spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})";
94 pb.set_style(
95 ProgressStyle::with_template(default)
96 .unwrap()
97 .progress_chars("#>-"),
98 );
99 pb.set_message(String::from(name));
100}