pkg/net_backend/
reqwest_backend.rs1use std::{
2 cell::RefCell,
3 fs::File,
4 io::{Read, Write},
5 path::Path,
6 rc::Rc,
7 time::Duration,
8};
9
10use super::{Callback, DownloadBackend, DownloadError};
11use reqwest::blocking::Client;
12
13#[derive(Clone)]
14pub struct ReqwestBackend {
15 client: Client,
16 client_no_brotli: Client,
17}
18
19impl DownloadBackend for ReqwestBackend {
20 fn new() -> Result<Self, DownloadError> {
21 let client = Client::builder()
22 .brotli(true)
23 .connect_timeout(Duration::new(5, 0))
24 .build()?;
25 let client_no_brotli = Client::builder()
26 .brotli(false)
27 .connect_timeout(Duration::new(5, 0))
28 .build()?;
29 Ok(Self {
30 client,
31 client_no_brotli,
32 })
33 }
34
35 fn download(
36 &self,
37 remote_path: &str,
38 local_path: &Path,
39 callback: Rc<RefCell<dyn Callback>>,
40 ) -> Result<(), DownloadError> {
41 let mut callback = callback.borrow_mut();
42
43 let mut resp = self.client.get(remote_path).send()?.error_for_status()?;
44
45 let len: u64 = resp.content_length().unwrap_or_else(|| {
46 self.client_no_brotli
47 .head(remote_path)
48 .send()
49 .ok()
50 .and_then(|resp_inner| {
51 resp_inner
52 .headers()
53 .get("content-length")
54 .and_then(|header| header.to_str().ok())
55 .and_then(|s| s.parse::<u64>().ok())
56 })
57 .unwrap_or(0)
58 });
59
60 let mut output = File::create(local_path)?;
61
62 callback.start_download(len, remote_path);
63
64 let mut data = [0; 8192];
65 loop {
66 let count = resp.read(&mut data)?;
67 output.write(&data[..count])?;
68 if count == 0 {
69 break;
70 }
71 callback.increment_downloaded(count);
72 }
73 output.flush()?;
74
75 callback.end_download();
76
77 Ok(())
78 }
79}