1#![cfg_attr(docs_rs, feature(doc_cfg, doc_auto_cfg))]
2#![doc = include_str!("../README.md")]
3
4mod error;
5
6use std::sync::Arc;
7
8pub use ureq;
9use ureq::{
10 config::Config,
11 http::Response,
12 tls::{RootCerts, TlsConfig, TlsProvider},
13 Agent, Body,
14};
15
16#[doc(inline)]
17pub use crate::error::{Error, Result};
18
19#[cfg(any(
20 all(feature = "tokio", feature = "async-std"),
21 not(any(feature = "tokio", feature = "async-std"))
22))]
23compile_error!("Either feature `tokio` or `async-std` must be enabled for this crate.");
24
25#[cfg(any(
26 all(feature = "rustls", feature = "native-tls"),
27 not(any(feature = "rustls", feature = "native-tls"))
28))]
29compile_error!("Either feature `rustls` or `native-tls` must be enabled for this crate.");
30
31#[derive(Clone, Debug)]
36pub struct Client {
37 agent: Arc<Agent>,
40}
41
42impl Client {
43 pub fn new() -> Self {
45 let tls = TlsConfig::builder()
46 .root_certs(RootCerts::PlatformVerifier)
47 .provider(
48 #[cfg(feature = "native-tls")]
49 TlsProvider::NativeTls,
50 #[cfg(feature = "rustls")]
51 TlsProvider::Rustls,
52 );
53
54 let config = Config::builder().tls_config(tls.build()).build();
55 let agent = Arc::new(config.new_agent());
56
57 Self { agent }
58 }
59
60 pub async fn send(
66 &self,
67 f: impl FnOnce(&Agent) -> std::result::Result<Response<Body>, ureq::Error> + Send + 'static,
68 ) -> Result<Response<Body>> {
69 let agent = self.agent.clone();
70
71 spawn_blocking(move || f(&agent))
72 .await?
73 .map_err(Error::SendRequestError)
74 }
75}
76
77#[cfg(feature = "async-std")]
79async fn spawn_blocking<F, T>(f: F) -> Result<T>
80where
81 F: FnOnce() -> T + Send + 'static,
82 T: Send + 'static,
83{
84 Ok(async_std::task::spawn_blocking(f).await)
85}
86
87#[cfg(feature = "tokio")]
89async fn spawn_blocking<F, T>(f: F) -> Result<T>
90where
91 F: FnOnce() -> T + Send + 'static,
92 T: Send + 'static,
93{
94 Ok(tokio::task::spawn_blocking(f).await?)
95}