use std::io::Read;
use std::time::Duration;
use crate::errors::Api2ConvertError;
pub struct HttpRequest {
pub method: String,
pub url: String,
pub headers: Vec<(String, String)>,
pub body: Option<Vec<u8>>,
#[allow(clippy::type_complexity)]
pub make_body: Option<Box<dyn Fn() -> std::io::Result<Box<dyn Read + Send>> + Send + Sync>>,
pub follow_redirects: bool,
pub replayable: bool,
pub timeout: Option<Duration>,
}
pub struct HttpResponse {
pub status: u16,
pub headers: Headers,
pub body: Box<dyn Read + Send>,
}
#[derive(Default, Clone)]
pub struct Headers(Vec<(String, String)>);
impl Headers {
pub fn new() -> Self {
Headers(Vec::new())
}
pub fn insert(&mut self, name: impl Into<String>, value: impl Into<String>) {
self.0
.push((name.into().to_ascii_lowercase(), value.into()));
}
pub fn get(&self, name: &str) -> Option<&str> {
let n = name.to_ascii_lowercase();
self.0
.iter()
.find(|(k, _)| *k == n)
.map(|(_, v)| v.as_str())
}
}
pub trait HttpSender: Send + Sync {
fn send(&self, req: &HttpRequest) -> Result<HttpResponse, Api2ConvertError>;
}
pub trait Sleeper: Send + Sync {
fn sleep(&self, dur: Duration);
}
pub trait Rng: Send + Sync {
fn next_f64(&self) -> f64;
}
pub(crate) struct ThreadSleeper;
impl Sleeper for ThreadSleeper {
fn sleep(&self, dur: Duration) {
if !dur.is_zero() {
std::thread::sleep(dur);
}
}
}
pub(crate) struct DefaultRng {
state: std::sync::atomic::AtomicU64,
}
impl DefaultRng {
pub(crate) fn new() -> Self {
use std::time::{SystemTime, UNIX_EPOCH};
let seed = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_nanos() as u64)
.unwrap_or(0x9E37_79B9_7F4A_7C15)
| 1;
DefaultRng {
state: std::sync::atomic::AtomicU64::new(seed),
}
}
}
impl Rng for DefaultRng {
fn next_f64(&self) -> f64 {
use std::sync::atomic::Ordering;
let mut x = self.state.load(Ordering::Relaxed);
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
self.state.store(x, Ordering::Relaxed);
((x >> 11) as f64) / ((1u64 << 53) as f64)
}
}