use crate::error::Result;
use crate::resolver::{ResolveOptions, ResolveOutcome, Resolver};
use crate::transport::{HttpResponse, HttpTransport, TransportError};
use async_trait::async_trait;
use std::time::Duration;
#[derive(Clone)]
pub struct ReqwestTransport {
client: reqwest::Client,
}
impl ReqwestTransport {
pub fn new() -> Self {
let client = reqwest::Client::builder()
.connect_timeout(Duration::from_secs(2))
.timeout(Duration::from_secs(30))
.build()
.expect("reqwest client builds with default TLS");
ReqwestTransport { client }
}
}
impl Default for ReqwestTransport {
fn default() -> Self {
Self::new()
}
}
type Result0<T> = core::result::Result<T, TransportError>;
async fn collect(resp: reqwest::Response) -> Result0<HttpResponse> {
let status = resp.status().as_u16();
let headers = resp
.headers()
.iter()
.map(|(k, v)| (k.as_str().to_string(), v.to_str().unwrap_or("").to_string()))
.collect();
let body = resp
.bytes()
.await
.map_err(|e| TransportError(e.to_string()))?
.to_vec();
Ok(HttpResponse {
status,
headers,
body,
})
}
#[async_trait(?Send)]
impl HttpTransport for ReqwestTransport {
async fn get(&self, url: &str) -> Result0<HttpResponse> {
let resp = self
.client
.get(url)
.send()
.await
.map_err(|e| TransportError(e.to_string()))?;
collect(resp).await
}
async fn post_json(&self, url: &str, body: String) -> Result0<HttpResponse> {
let resp = self
.client
.post(url)
.header("content-type", "application/json")
.body(body)
.send()
.await
.map_err(|e| TransportError(e.to_string()))?;
collect(resp).await
}
}
pub async fn resolve(urn: &str) -> Result<ResolveOutcome> {
resolve_with(urn, ResolveOptions::default()).await
}
pub async fn resolve_with(urn: &str, options: ResolveOptions) -> Result<ResolveOutcome> {
Resolver::with_options(ReqwestTransport::new(), options)
.resolve(urn)
.await
}
pub fn resolve_blocking(urn: &str) -> Result<ResolveOutcome> {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("current-thread tokio runtime builds");
rt.block_on(resolve(urn))
}