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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use super::SparseIndex;
use crate::{Error, IndexKrate, KrateName};
pub use reqwest::blocking::Client;
pub use reqwest::Client as AsyncClient;

/// Allows **blocking** access to a remote HTTP sparse registry index
pub struct RemoteSparseIndex {
    /// The local index this remote is wrapping
    pub index: SparseIndex,
    /// The client used to make requests to the remote index
    pub client: Client,
}

impl RemoteSparseIndex {
    /// Creates a new [`Self`] that can access and write local cache entries,
    /// and contact the remote index to retrieve the latest index information
    #[inline]
    pub fn new(index: SparseIndex, client: Client) -> Self {
        Self { index, client }
    }

    /// Gets the latest index metadata for the crate
    ///
    /// Network I/O is _always_ performed when calling this method, however the
    /// response from the remote registry will be empty of contents other than
    /// headers if the local cache entry for the crate is up to date with the
    /// latest in the index
    pub fn krate(
        &self,
        name: KrateName<'_>,
        write_cache_entry: bool,
    ) -> Result<Option<IndexKrate>, Error> {
        let req = self.index.make_remote_request(name)?;
        let req = req.try_into()?;

        let res = self.client.execute(req)?;

        let mut builder = http::Response::builder()
            .status(res.status())
            .version(res.version());

        builder
            .headers_mut()
            .unwrap()
            .extend(res.headers().iter().map(|(k, v)| (k.clone(), v.clone())));

        let body = res.bytes()?;
        let res = builder.body(body.to_vec())?;

        self.index
            .parse_remote_response(name, res, write_cache_entry)
    }

    /// Attempts to read the locally cached crate information
    ///
    /// This method does no network I/O unlike [`Self::krate`], but does not
    /// guarantee that the cache information is up to date with the latest in
    /// the remote index
    #[inline]
    pub fn cached_krate(&self, name: KrateName<'_>) -> Result<Option<IndexKrate>, Error> {
        self.index.cached_krate(name)
    }
}

/// Allows **async** access to a remote HTTP sparse registry index
pub struct AsyncRemoteSparseIndex {
    /// The local index this remote is wrapping
    pub index: SparseIndex,
    /// The client used to make requests to the remote index
    pub client: AsyncClient,
}

impl AsyncRemoteSparseIndex {
    /// Creates a new [`Self`] that can access and write local cache entries,
    /// and contact the remote index to retrieve the latest index information
    #[inline]
    pub fn new(index: SparseIndex, client: AsyncClient) -> Self {
        Self { index, client }
    }

    /// Async version of [`RemoteSparseIndex::krate`]
    pub async fn krate_async(
        &self,
        name: KrateName<'_>,
        write_cache_entry: bool,
    ) -> Result<Option<IndexKrate>, Error> {
        let req = self.index.make_remote_request(name)?;
        let req = req.try_into()?;

        let res = self.client.execute(req).await?;

        let mut builder = http::Response::builder()
            .status(res.status())
            .version(res.version());

        builder
            .headers_mut()
            .unwrap()
            .extend(res.headers().iter().map(|(k, v)| (k.clone(), v.clone())));

        let body = res.bytes().await?;
        let res = builder.body(body.to_vec())?;

        self.index
            .parse_remote_response(name, res, write_cache_entry)
    }

    /// Attempts to read the locally cached crate information
    ///
    /// This method does no network I/O unlike [`Self::krate_async`], but does not
    /// guarantee that the cache information is up to date with the latest in
    /// the remote index
    #[inline]
    pub fn cached_krate(&self, name: KrateName<'_>) -> Result<Option<IndexKrate>, Error> {
        self.index.cached_krate(name)
    }
}

impl From<reqwest::Error> for Error {
    #[inline]
    fn from(e: reqwest::Error) -> Self {
        Self::Http(crate::HttpError::Reqwest(e))
    }
}

impl From<http::Error> for Error {
    #[inline]
    fn from(e: http::Error) -> Self {
        Self::Http(crate::HttpError::Http(e))
    }
}