cleanup futures
This commit is contained in:
parent
c819ec8dde
commit
260c1ee8c6
|
@ -3,9 +3,40 @@ use std::collections::HashMap;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use url::form_urlencoded;
|
use url::form_urlencoded;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
pub type PropertyMap = HashMap<&'static str, Jss>;
|
pub type PropertyMap = HashMap<&'static str, Jss>;
|
||||||
|
|
||||||
|
#[derive(Debug, Fail)]
|
||||||
|
pub struct ParameterError {
|
||||||
|
error_list: Vec<Error>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParameterError {
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
Self { error_list: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&mut self, value: Error) {
|
||||||
|
self.error_list.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.error_list.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ParameterError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let msg = self.error_list.iter().fold(String::from(""), |acc, item| {
|
||||||
|
acc + &item.to_string() + "\n"
|
||||||
|
});
|
||||||
|
|
||||||
|
write!(f, "{}", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct JssBoolean {
|
pub struct JssBoolean {
|
||||||
pub description: &'static str,
|
pub description: &'static str,
|
||||||
|
@ -200,13 +231,13 @@ fn parse_simple_value(value_str: &str, schema: &Jss) -> Result<Value, Error> {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_parameter_strings(data: &Vec<(String, String)>, schema: &Jss, test_required: bool) -> Result<Value, Vec<Error>> {
|
pub fn parse_parameter_strings(data: &Vec<(String, String)>, schema: &Jss, test_required: bool) -> Result<Value, ParameterError> {
|
||||||
|
|
||||||
println!("QUERY Strings {:?}", data);
|
println!("QUERY Strings {:?}", data);
|
||||||
|
|
||||||
let mut params = json!({});
|
let mut params = json!({});
|
||||||
|
|
||||||
let mut errors: Vec<Error> = Vec::new();
|
let mut errors = ParameterError::new();
|
||||||
|
|
||||||
match schema {
|
match schema {
|
||||||
Jss::Object(JssObject { properties, additional_properties, .. }) => {
|
Jss::Object(JssObject { properties, additional_properties, .. }) => {
|
||||||
|
@ -282,14 +313,14 @@ pub fn parse_parameter_strings(data: &Vec<(String, String)>, schema: &Jss, test_
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errors.len() > 0) {
|
if errors.len() > 0 {
|
||||||
Err(errors)
|
Err(errors)
|
||||||
} else {
|
} else {
|
||||||
Ok(params)
|
Ok(params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_query_string(query: &str, schema: &Jss, test_required: bool) -> Result<Value, Vec<Error>> {
|
pub fn parse_query_string(query: &str, schema: &Jss, test_required: bool) -> Result<Value, ParameterError> {
|
||||||
|
|
||||||
let param_list: Vec<(String, String)> =
|
let param_list: Vec<(String, String)> =
|
||||||
form_urlencoded::parse(query.as_bytes()).into_owned().collect();
|
form_urlencoded::parse(query.as_bytes()).into_owned().collect();
|
||||||
|
|
146
src/main.rs
146
src/main.rs
|
@ -10,7 +10,7 @@ use apitest::api_info::*;
|
||||||
use apitest::json_schema::*;
|
use apitest::json_schema::*;
|
||||||
|
|
||||||
//use serde_derive::{Serialize, Deserialize};
|
//use serde_derive::{Serialize, Deserialize};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json};
|
||||||
|
|
||||||
//use hyper::body::Payload;
|
//use hyper::body::Payload;
|
||||||
use hyper::http::request::Parts;
|
use hyper::http::request::Parts;
|
||||||
|
@ -20,19 +20,19 @@ use hyper::service::service_fn;
|
||||||
|
|
||||||
use futures::future;
|
use futures::future;
|
||||||
|
|
||||||
type BoxFut = Box<Future<Item = Response<Body>, Error = hyper::Error> + Send>;
|
type BoxFut = Box<Future<Item = Response<Body>, Error = failure::Error> + Send>;
|
||||||
|
|
||||||
macro_rules! http_error {
|
macro_rules! error_response {
|
||||||
($status:ident, $msg:expr) => {{
|
($status:ident, $msg:expr) => {{
|
||||||
let mut resp = Response::new(Body::from($msg));
|
let mut resp = Response::new(Body::from($msg));
|
||||||
*resp.status_mut() = StatusCode::$status;
|
*resp.status_mut() = StatusCode::$status;
|
||||||
return resp
|
resp
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! http_error_future {
|
macro_rules! http_error_future {
|
||||||
($status:ident, $msg:expr) => {{
|
($status:ident, $msg:expr) => {{
|
||||||
let mut resp = Response::new(Body::from($msg));
|
let resp = error_response!($status, $msg);
|
||||||
*resp.status_mut() = StatusCode::$status;
|
|
||||||
return Box::new(futures::future::ok(resp));
|
return Box::new(futures::future::ok(resp));
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -41,62 +41,52 @@ fn handle_api_request<'a>(
|
||||||
info: &'a ApiMethod,
|
info: &'a ApiMethod,
|
||||||
parts: Parts,
|
parts: Parts,
|
||||||
req_body: Body,
|
req_body: Body,
|
||||||
) -> Box<Future<Item = Response<Body>, Error = hyper::Error> + Send + 'a>
|
) -> Box<Future<Item = Response<Body>, Error = failure::Error> + Send + 'a>
|
||||||
{
|
{
|
||||||
|
let resp = req_body.concat2()
|
||||||
|
.map_err(|err| format_err!("Promlems reading request body: {}", err))
|
||||||
|
.and_then(move |body| {
|
||||||
|
|
||||||
let entire_body = req_body.concat2();
|
let bytes = String::from_utf8(body.to_vec())?; // why copy??
|
||||||
|
|
||||||
let resp = entire_body.map(move |body| {
|
println!("GOT BODY {:?}", bytes);
|
||||||
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 {:?}", bytes);
|
let mut test_required = true;
|
||||||
|
|
||||||
let mut test_required = true;
|
let mut params = json!({});
|
||||||
|
|
||||||
let mut params = json!({});
|
if bytes.len() > 0 {
|
||||||
|
params = parse_query_string(&bytes, &info.parameters, true)?;
|
||||||
let format_error_list = |error_list: Vec<Error>| {
|
test_required = false;
|
||||||
error_list.iter().fold(String::from(""), |acc, item| {
|
|
||||||
acc + &item.to_string() + "\n"
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
if bytes.len() > 0 {
|
|
||||||
params = match parse_query_string(&bytes, &info.parameters, true) {
|
|
||||||
Ok(value) => value,
|
|
||||||
Err(error_list) => http_error!(NOT_FOUND, format_error_list(error_list)),
|
|
||||||
};
|
|
||||||
test_required = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(query_str) = parts.uri.query() {
|
|
||||||
let query_params = match parse_query_string(query_str, &info.parameters, test_required) {
|
|
||||||
Ok(value) => value,
|
|
||||||
Err(error_list) => http_error!(NOT_FOUND, format_error_list(error_list)),
|
|
||||||
};
|
|
||||||
|
|
||||||
for (k, v) in query_params.as_object().unwrap() {
|
|
||||||
params[k] = v.clone(); // fixme: why clone()??
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(query_str) = parts.uri.query() {
|
||||||
|
let query_params = parse_query_string(query_str, &info.parameters, test_required)?;
|
||||||
|
|
||||||
|
for (k, v) in query_params.as_object().unwrap() {
|
||||||
|
params[k] = v.clone(); // fixme: why clone()??
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("GOT PARAMS {}", params);
|
||||||
|
|
||||||
|
let res = (info.handler)(params, info)?;
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
|
||||||
|
}).then(|result| {
|
||||||
|
match result {
|
||||||
|
Ok(ref value) => {
|
||||||
|
let json_str = value.to_string();
|
||||||
|
|
||||||
|
Ok(Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.header("ContentType", "application/json")
|
||||||
|
.body(Body::from(json_str))
|
||||||
|
.unwrap()) // fixme: really?
|
||||||
|
}
|
||||||
|
Err(err) => Ok(error_response!(NOT_FOUND, err.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("GOT PARAMS {}", params);
|
|
||||||
|
|
||||||
let res: Value = match (info.handler)(params, info) {
|
|
||||||
Ok(res) => res,
|
|
||||||
Err(err) => http_error!(NOT_FOUND, format!("Method returned error '{}'\n", err)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let json_str = res.to_string();
|
|
||||||
|
|
||||||
Response::builder()
|
|
||||||
.status(200)
|
|
||||||
.header("ContentType", "application/json")
|
|
||||||
.body(Body::from(json_str))
|
|
||||||
.unwrap() // fixme: really?
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Box::new(resp)
|
Box::new(resp)
|
||||||
|
@ -139,43 +129,8 @@ fn handle_request(req: Request<Body>) -> BoxFut {
|
||||||
|
|
||||||
// fixme: handle auth
|
// fixme: handle auth
|
||||||
|
|
||||||
|
return handle_api_request(api_method, parts, body);
|
||||||
|
|
||||||
let res = handle_api_request(api_method, parts, body);
|
|
||||||
return res;
|
|
||||||
|
|
||||||
/*
|
|
||||||
// extract param
|
|
||||||
let param = match query {
|
|
||||||
Some(data) => {
|
|
||||||
match parse_query_string(data, &api_method.parameters, true) {
|
|
||||||
Ok(query) => query,
|
|
||||||
Err(ref error_list) => {
|
|
||||||
let msg = error_list.iter().fold(String::from(""), |acc, item| {
|
|
||||||
acc + &item.to_string() + "\n"
|
|
||||||
});
|
|
||||||
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_future!(NOT_FOUND, format!("Method returned error '{}'\n", err));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
} else {
|
} else {
|
||||||
http_error_future!(NOT_FOUND, format!("No such path '{}'\n", path));
|
http_error_future!(NOT_FOUND, format!("No such path '{}'\n", path));
|
||||||
}
|
}
|
||||||
|
@ -195,8 +150,15 @@ fn main() {
|
||||||
let addr = ([127, 0, 0, 1], 8007).into();
|
let addr = ([127, 0, 0, 1], 8007).into();
|
||||||
|
|
||||||
let new_svc = || {
|
let new_svc = || {
|
||||||
// service_fn_ok converts our function into a `Service`
|
service_fn(|req| {
|
||||||
service_fn(handle_request)
|
// clumsy way to convert failure::Error to Response
|
||||||
|
handle_request(req).then(|result| -> Result<Response<Body>, String> {
|
||||||
|
match result {
|
||||||
|
Ok(res) => Ok(res),
|
||||||
|
Err(err) => Ok(error_response!(NOT_FOUND, err.to_string())),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let server = Server::bind(&addr)
|
let server = Server::bind(&addr)
|
||||||
|
|
Loading…
Reference in New Issue