duvet_core/
http.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5    contents::Contents,
6    diagnostic::IntoDiagnostic,
7    file::{BinaryFile, SourceFile},
8    path::Path,
9    Cache, Query, Result,
10};
11use std::sync::Arc;
12
13pub use http::response::Parts;
14pub use reqwest::Client;
15
16fn default_headers() -> reqwest::header::HeaderMap {
17    let mut map = reqwest::header::HeaderMap::new();
18
19    map.insert("accept", "text/plain".parse().unwrap());
20
21    map
22}
23
24pub fn client() -> Query<Client> {
25    #[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
26    struct Q;
27
28    Cache::current().get_or_init(Q, || {
29        Query::from(
30            Client::builder()
31                .user_agent(concat!(
32                    env!("CARGO_PKG_NAME"),
33                    "/",
34                    env!("CARGO_PKG_VERSION")
35                ))
36                .default_headers(default_headers())
37                .build()
38                .unwrap(),
39        )
40    })
41}
42
43pub fn get_full<U>(url: U) -> Query<Result<(Arc<Parts>, Contents)>>
44where
45    U: 'static + Clone + AsRef<str> + Send + Sync,
46{
47    Cache::current().get_or_init(url.as_ref().to_string(), move || {
48        Query::new(async move {
49            let client = client().await;
50
51            let resp = client.get(url.as_ref()).send().await.into_diagnostic()?;
52            let mut resp = resp.error_for_status().into_diagnostic()?;
53
54            let mut body = vec![];
55
56            while let Some(chunk) = resp.chunk().await.into_diagnostic()? {
57                body.extend_from_slice(&chunk);
58            }
59
60            let resp: http::Response<reqwest::Body> = resp.into();
61
62            let (headers, _) = resp.into_parts();
63
64            let headers = Arc::new(headers);
65            let body = Contents::from(body);
66
67            Ok((headers, body))
68        })
69    })
70}
71
72pub fn get<U>(url: U) -> Query<Result<Contents>>
73where
74    U: 'static + Clone + AsRef<str> + Send + Sync,
75{
76    Query::new(async move {
77        let resp = get_full(url).await?;
78        Ok(resp.1)
79    })
80}
81
82pub fn get_cached<U, P>(url: U, cached_path: P) -> Query<Result<BinaryFile>>
83where
84    U: 'static + Clone + AsRef<str> + Send + Sync,
85    P: Into<Path>,
86{
87    crate::vfs::read_file_or_create(cached_path, get(url))
88}
89
90pub fn get_cached_string<U, P>(url: U, cached_path: P) -> Query<Result<SourceFile>>
91where
92    U: 'static + Clone + AsRef<str> + Send + Sync,
93    P: Into<Path>,
94{
95    crate::vfs::read_string_or_create(cached_path, get(url))
96}