1pub use anyhow::{anyhow, Result};
2use futures::future::BoxFuture;
3use isahc::{
4 config::{Configurable, RedirectPolicy},
5 AsyncBody,
6};
7pub use isahc::{
8 http::{Method, Uri},
9 Error,
10};
11use smol::future::FutureExt;
12use std::{sync::Arc, time::Duration};
13pub use url::Url;
14
15pub type Request = isahc::Request<AsyncBody>;
16pub type Response = isahc::Response<AsyncBody>;
17
18pub trait HttpClient: Send + Sync {
19 fn send(&self, req: Request) -> BoxFuture<Result<Response, Error>>;
20
21 fn get<'a>(
22 &'a self,
23 uri: &str,
24 body: AsyncBody,
25 follow_redirects: bool,
26 ) -> BoxFuture<'a, Result<Response, Error>> {
27 let request = isahc::Request::builder()
28 .redirect_policy(if follow_redirects {
29 RedirectPolicy::Follow
30 } else {
31 RedirectPolicy::None
32 })
33 .method(Method::GET)
34 .uri(uri)
35 .body(body);
36 match request {
37 Ok(request) => self.send(request),
38 Err(error) => async move { Err(error.into()) }.boxed(),
39 }
40 }
41}
42
43pub fn client() -> Arc<dyn HttpClient> {
44 Arc::new(
45 isahc::HttpClient::builder()
46 .connect_timeout(Duration::from_secs(5))
47 .low_speed_timeout(100, Duration::from_secs(5))
48 .build()
49 .unwrap(),
50 )
51}
52
53impl HttpClient for isahc::HttpClient {
54 fn send(&self, req: Request) -> BoxFuture<Result<Response, Error>> {
55 Box::pin(async move { self.send_async(req).await })
56 }
57}