rustup_available_packages/
downloader.rs1use super::skip_errors::SkipMissingExt;
2use crate::{
3 cache::FsCache,
4 manifest::Manifest,
5 source::{DefaultSource, SourceInfo},
6 Error,
7};
8use chrono::{Duration, NaiveDate};
9use std::{io, iter};
10
11pub struct Downloader<S> {
13 client: reqwest::blocking::Client,
14 source: S,
15 cache: FsCache,
16 skip_missing_days: usize,
17}
18
19impl<'a> Downloader<DefaultSource<'a>> {
20 pub fn with_default_source(channel: &'a str) -> Self {
22 Self::new(DefaultSource::new(channel))
23 }
24}
25
26impl<S> Downloader<S> {
27 pub fn new(source: S) -> Self {
29 Downloader {
30 client: reqwest::blocking::Client::new(),
31 source,
32 cache: FsCache::noop(),
33 skip_missing_days: 0,
34 }
35 }
36}
37
38impl<S> Downloader<S>
39where
40 S: SourceInfo,
41{
42 pub fn set_cache(self, c: FsCache) -> Downloader<S> {
44 Downloader {
45 client: self.client,
46 source: self.source,
47 cache: c,
48 skip_missing_days: self.skip_missing_days,
49 }
50 }
51
52 pub fn skip_missing_days(self, skip: usize) -> Downloader<S> {
58 Downloader {
59 client: self.client,
60 source: self.source,
61 cache: self.cache,
62 skip_missing_days: skip,
63 }
64 }
65
66 pub fn get_last_manifests(&self, days: usize) -> Result<Vec<Manifest>, Error> {
71 let latest = self.get_latest_manifest()?;
72 let latest_day = latest.date;
73 log::info!("Latest manifest is for {}", latest_day);
74 let rest = (1..days)
75 .filter_map(|day| latest_day.checked_sub_signed(Duration::days(day as i64)))
76 .map(|date| self.get_manifest(date))
77 .skip_missing(self.skip_missing_days);
78 iter::once(Ok(latest)).chain(rest).collect()
79 }
80
81 pub fn get_manifest(&self, day: NaiveDate) -> Result<Manifest, Error> {
83 if let Some(cached) = self.cache.get(day) {
84 return Ok(cached);
85 }
86 let manifest = self.get_manifest_by_url(self.source.make_manifest_url(day))?;
87 self.cache.store(&manifest);
88 Ok(manifest)
89 }
90
91 pub fn get_latest_manifest(&self) -> Result<Manifest, Error> {
96 self.get_manifest_by_url(self.source.make_latest_manifest_url())
97 }
98
99 pub fn get_manifest_by_url(&self, url: impl AsRef<str>) -> Result<Manifest, Error> {
103 let url = url.as_ref();
104 log::info!("Fetching a manifest from {}", url);
105 let mut response = self
106 .client
107 .get(url)
108 .send()
109 .map_err(|e| Error::Reqwest(e, url.into()))?;
110 if !response.status().is_success() {
111 return Err(Error::BadResponse(response.status(), url.into()));
112 }
113 let mut bytes = Vec::new();
114 io::copy(&mut response, &mut bytes).map_err(|e| Error::Io(e, url.into()))?;
115
116 toml::from_slice(&bytes).map_err(|e| Error::TomlDe(e, url.to_string()))
117 }
118}