diff --git a/Cargo.toml b/Cargo.toml index cff7da10..55cebade 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,8 @@ serde = "1.0.80" serde_json = "1.0.32" serde_derive = "1.0.80" url = "1.7.1" -hyper = "0.12.13" +futures = "0.1.25" +http = "0.1.13" +hyper = "0.12.14" lazy_static = "1.1.0" regex = "1.0.6" diff --git a/src/main.rs b/src/main.rs index 234fa58b..21f0aa37 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,24 +13,73 @@ use apitest::json_schema::*; use serde_json::{json, Value}; +use hyper::body::Payload; +use hyper::http::request::Parts; use hyper::{Method, Body, Request, Response, Server, StatusCode}; -use hyper::rt::Future; -use hyper::service::service_fn_ok; +use hyper::rt::{Future, Stream}; +use hyper::service::service_fn; + +use futures::prelude::*; +use futures::future; + +use http; +use std::io; + +type BoxFut = Box, Error = hyper::Error> + Send>; macro_rules! http_error { ($status:ident, $msg:expr) => {{ let mut resp = Response::new(Body::from($msg)); *resp.status_mut() = StatusCode::$status; - return resp; + return resp + }} +} +macro_rules! http_error_future { + ($status:ident, $msg:expr) => {{ + let mut resp = Response::new(Body::from($msg)); + *resp.status_mut() = StatusCode::$status; + return Box::new(futures::future::ok(resp)); }} } +fn handle_api_request<'a>( + info: &'a ApiMethod, parts: Parts, req_body: Body, query: Option) + -> Box, Error = hyper::Error> + Send + 'a> +{ -fn handle_request(req: Request) -> Response { + let entire_body = req_body.concat2(); + + let resp = entire_body.map(move |body| { + let bytes = match String::from_utf8(body.to_vec()) { // why copy?? + Ok(v) => v, + Err(err) => http_error!(NOT_FOUND, err.to_string()), + }; + + println!("GOT BODY {:?}", parts); + + match parse_query_string(&bytes, &info.parameters, true) { + Ok(res) => { + let json_str = res.to_string(); + return Response::new(Body::from(json_str)); + } + Err(err) => { + http_error!(NOT_FOUND, format!("Method returned error '{:?}'\n", err)); + } + } + + }); + + Box::new(resp) +} + +fn handle_request(req: Request) -> BoxFut { + + let (parts, body) = req.into_parts(); + + let method = parts.method.clone(); + let path = parts.uri.path(); + let query = parts.uri.query().map(|x| x.to_owned()); - let method = req.method(); - let path = req.uri().path(); - let query = req.uri().query(); let components: Vec<&str> = path.split('/').filter(|x| !x.is_empty()).collect(); let comp_len = components.len(); @@ -42,25 +91,30 @@ fn handle_request(req: Request) -> Response { if comp_len >= 2 { let format = components[1]; if format != "json" { - http_error!(NOT_FOUND, format!("Unsupported format '{}'\n", format)) + http_error_future!(NOT_FOUND, format!("Unsupported format '{}'\n", format)) } if let Some(info) = ROUTER.find_method(&components[2..]) { println!("FOUND INFO"); let api_method_opt = match method { - &Method::GET => &info.get, - &Method::PUT => &info.put, - &Method::POST => &info.post, - &Method::DELETE => &info.delete, + Method::GET => &info.get, + Method::PUT => &info.put, + Method::POST => &info.post, + Method::DELETE => &info.delete, _ => &None, }; let api_method = match api_method_opt { Some(m) => m, - _ => http_error!(NOT_FOUND, format!("No such method '{} {}'\n", method, path)), + _ => http_error_future!(NOT_FOUND, format!("No such method '{} {}'\n", method, path)), }; // fixme: handle auth + + let res = handle_api_request(api_method, parts, body, query); + return res; + + /* // extract param let param = match query { Some(data) => { @@ -70,30 +124,36 @@ fn handle_request(req: Request) -> Response { let msg = error_list.iter().fold(String::from(""), |acc, item| { acc + &item.to_string() + "\n" }); - http_error!(BAD_REQUEST, msg); + http_error_future!(BAD_REQUEST, msg); } } } None => json!({}), }; + + /*if body.is_end_stream() { + println!("NO BODY"); + }*/ + match (api_method.handler)(param, &api_method) { Ok(res) => { let json_str = res.to_string(); return Response::new(Body::from(json_str)); } Err(err) => { - http_error!(NOT_FOUND, format!("Method returned error '{}'\n", err)); + http_error_future!(NOT_FOUND, format!("Method returned error '{}'\n", err)); } } +*/ } else { - http_error!(NOT_FOUND, format!("No such path '{}'\n", path)); + http_error_future!(NOT_FOUND, format!("No such path '{}'\n", path)); } } } - Response::new(Body::from("RETURN WEB GUI\n")) + Box::new(future::ok(Response::new(Body::from("RETURN WEB GUI\n")))) } lazy_static!{ @@ -107,7 +167,7 @@ fn main() { let new_svc = || { // service_fn_ok converts our function into a `Service` - service_fn_ok(handle_request) + service_fn(handle_request) }; let server = Server::bind(&addr)