pub mod socket;
use crate::client::{Http, Method, Request, Response, TransportError};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
pub use socket::{Event, Feed, FeedError};
pub const TIMEOUT: Duration = Duration::from_secs(30);
#[derive(Debug, Clone)]
pub struct Native {
client: reqwest::Client,
}
impl Native {
#[must_use]
pub fn new() -> Self {
Native::with_timeout(TIMEOUT)
}
#[must_use]
pub fn with_timeout(timeout: Duration) -> Self {
let client = reqwest::Client::builder().timeout(timeout).build().unwrap_or_else(|_| reqwest::Client::new());
Native { client }
}
}
impl Default for Native {
fn default() -> Self {
Native::new()
}
}
impl Http for Native {
async fn send(&self, request: Request) -> Result<Response, TransportError> {
let unreachable = |error: reqwest::Error| TransportError::Unreachable(error.without_url().to_string());
let mut outgoing = self.client.request(method(request.method), &request.url);
for (name, value) in &request.headers {
outgoing = outgoing.header(name, value);
}
if !request.body.is_empty() {
outgoing = outgoing.body(request.body);
}
let answer = outgoing.send().await.map_err(unreachable)?;
let status = answer.status().as_u16();
let headers = answer
.headers()
.iter()
.map(|(name, value)| (name.as_str().to_owned(), String::from_utf8_lossy(value.as_bytes()).into_owned()))
.collect();
let body = answer.bytes().await.map_err(unreachable)?.to_vec();
Ok(Response { status, headers, body })
}
}
fn method(method: Method) -> reqwest::Method {
match method {
Method::Get => reqwest::Method::GET,
Method::Post => reqwest::Method::POST,
}
}
#[must_use]
pub fn clock() -> u64 {
SystemTime::now().duration_since(UNIX_EPOCH).map_or(0, |since| u64::try_from(since.as_millis()).unwrap_or(u64::MAX))
}
#[cfg(test)]
#[path = "tests/http.rs"]
mod tests;