use std::thread;
use std::time::Duration;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use hyper;
use hyper::Client;
use hyper::method::Method;
use super::request::HttpRequest;
pub trait HttpApi: Send + Copy + Default {
fn start(&self);
fn hostname(&self) -> &'static str;
fn port(&self) -> u16;
fn host(&self) -> String {
format!("{}:{}", self.hostname(), self.port())
}
fn protocol(&self) -> &'static str {
match self.port() {
443 => "https",
_ => "http"
}
}
fn url(&self) -> String {
match self.port() {
443 | 80 => format!("{}://{}", self.protocol(), self.hostname()),
_ => format!("{}://{}", self.protocol(), self.host())
}
}
fn url_with_path(&self, path: &str) -> String {
format!("{}{}", self.url(), path)
}
fn options(path: &'static str) -> HttpRequest<Self> where Self: 'static {
request(Self::default(), Method::Options, path)
}
fn get(path: &'static str) -> HttpRequest<Self> where Self: 'static {
request(Self::default(), Method::Get, path)
}
fn post(path: &'static str) -> HttpRequest<Self> where Self: 'static {
request(Self::default(), Method::Post, path)
}
fn put(path: &'static str) -> HttpRequest<Self> where Self: 'static {
request(Self::default(), Method::Put, path)
}
fn delete(path: &'static str) -> HttpRequest<Self> where Self: 'static {
request(Self::default(), Method::Delete, path)
}
fn head(path: &'static str) -> HttpRequest<Self> where Self: 'static {
request(Self::default(), Method::Head, path)
}
fn trace(path: &'static str) -> HttpRequest<Self> where Self: 'static {
request(Self::default(), Method::Trace, path)
}
fn connect(path: &'static str) -> HttpRequest<Self> where Self: 'static {
request(Self::default(), Method::Connect, path)
}
fn patch(path: &'static str) -> HttpRequest<Self> where Self: 'static {
request(Self::default(), Method::Patch, path)
}
fn ext(http_verb: &'static str, path: &'static str) -> HttpRequest<Self> where Self: 'static {
request(Self::default(), Method::Extension(http_verb.to_string()), path)
}
}
fn request<A: HttpApi + 'static>(
api: A,
method: Method,
path: &'static str
) -> HttpRequest<A> {
let mut api_timed_out = false;
if let Ok(started) = API_THREAD_STARTED.lock() {
if !started.load(Ordering::Relaxed) {
started.store(true, Ordering::Relaxed);
thread::spawn(move || {
api.start();
});
let mut ticks = 0;
while ticks < 100 {
let client = Client::new();
match client.head(api.url().as_str()).send() {
Err(hyper::Error::Io(_)) => { },
_ => break
}
thread::sleep(Duration::from_millis(10));
ticks += 1;
}
if ticks == 100 {
api_timed_out = true;
}
}
}
super::request::http_request(api, method, path, api_timed_out)
}
lazy_static! {
static ref API_THREAD_STARTED: Arc<Mutex<AtomicBool>> = {
Arc::new(Mutex::new(AtomicBool::new(false)))
};
}