summaryrefslogtreecommitdiffstats
path: root/examples/download_progress/src/downloader.rs
blob: 62f943fd7ee6096ac8811ddffa713b8446ea1bee (plain) (blame)
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
use iced_futures::futures;

// Just a little utility function
pub fn file<T: ToString>(url: T) -> iced::Subscription<DownloadMessage> {
    iced::Subscription::from_recipe(Downloader {
        url: url.to_string(),
    })
}

pub struct Downloader {
    url: String,
}

// Make sure iced can use our download stream
impl<H, I> iced_native::subscription::Recipe<H, I> for Downloader
where
    H: std::hash::Hasher,
{
    type Output = DownloadMessage;

    fn hash(&self, state: &mut H) {
        use std::hash::Hash;
        std::any::TypeId::of::<Self>().hash(state);
    }

    fn stream(
        self: Box<Self>,
        _input: futures::stream::BoxStream<'static, I>,
    ) -> futures::stream::BoxStream<'static, Self::Output> {
        use isahc::prelude::*;

        Box::pin(futures::stream::unfold(
            DownloadState::Ready(self.url),
            |state| async move {
                match state {
                    DownloadState::Ready(url) => {
                        let resp = Request::get(&url)
                            .metrics(true)
                            .body(())
                            .unwrap()
                            .send_async()
                            .await
                            .unwrap();
                        let metrics = resp.metrics().unwrap().clone();
                        // If you actually want to download:
                        /*let file = async_std::fs::File::create("download.bin")
                        .await
                        .unwrap();*/

                        async_std::task::spawn(async_std::io::copy(
                            resp.into_body(),
                            async_std::io::sink(), //file
                        ));

                        Some((
                            DownloadMessage::DownloadStarted,
                            DownloadState::Downloading(metrics),
                        ))
                    }
                    DownloadState::Downloading(metrics) => {
                        async_std::task::sleep(
                            std::time::Duration::from_millis(100),
                        )
                        .await;

                        let percentage = metrics.download_progress().0 * 100
                            / metrics.download_progress().1;

                        if percentage == 100 {
                            Some((
                                DownloadMessage::Done,
                                DownloadState::Finished,
                            ))
                        } else {
                            Some((
                                DownloadMessage::Downloading(percentage),
                                DownloadState::Downloading(metrics),
                            ))
                        }
                    }
                    DownloadState::Finished => None,
                }
            },
        ))
    }
}

#[derive(Debug)]
pub enum DownloadMessage {
    DownloadStarted,
    Downloading(u64),
    Done,
}

pub enum DownloadState {
    Ready(String),
    Downloading(isahc::Metrics),
    Finished,
}