start implementing request handler

This commit is contained in:
Dietmar Maurer 2018-11-01 11:30:49 +01:00
parent 886e5ce8f7
commit 28e47cea55
3 changed files with 90 additions and 6 deletions

View File

@ -19,4 +19,5 @@ derive-new = "0.5.5"
serde = "1.0.80" serde = "1.0.80"
serde_json = "1.0.32" serde_json = "1.0.32"
serde_derive = "1.0.80" serde_derive = "1.0.80"
url = "1.7.1"
hyper = "0.12.13" hyper = "0.12.13"

View File

@ -27,4 +27,18 @@ pub static METHOD_INFO_DEFAULTS: MethodInfo = MethodInfo {
delete: None, delete: None,
subdirs: None, subdirs: None,
}; };
pub fn find_method_info<'a>(root: &'a MethodInfo, components: &[&str]) -> Option<&'a MethodInfo> {
if components.len() == 0 { return Some(root); };
let (dir, rest) = (components[0], &components[1..]);
if let Some(dirmap) = root.subdirs {
if let Some(info) = dirmap.get(dir) {
return find_method_info(info, rest);
}
}
None
}

View File

@ -5,6 +5,8 @@ extern crate phf;
extern crate failure; extern crate failure;
use failure::*; use failure::*;
use std::collections::HashMap;
#[macro_use] #[macro_use]
extern crate apitest; extern crate apitest;
@ -18,9 +20,13 @@ extern crate serde_derive;
use serde_json::{json, Value}; use serde_json::{json, Value};
extern crate url;
use url::form_urlencoded;
extern crate hyper; extern crate hyper;
use hyper::{Body, Request, Response, Server}; use hyper::{Method, Body, Request, Response, Server, StatusCode};
use hyper::rt::Future; use hyper::rt::Future;
use hyper::service::service_fn_ok; use hyper::service::service_fn_ok;
@ -91,6 +97,7 @@ static TEST_API_METHOD: ApiMethod = ApiMethod {
description: "This is a simple test.", description: "This is a simple test.",
properties: phf_map! { properties: phf_map! {
"force" => Boolean!{ "force" => Boolean!{
optional => Some(true),
description => "Test for boolean options." description => "Test for boolean options."
} }
}, },
@ -104,21 +111,83 @@ static API3_NODES: MethodInfo = MethodInfo {
..METHOD_INFO_DEFAULTS ..METHOD_INFO_DEFAULTS
}; };
static API3: MethodInfo = MethodInfo { static API_ROOT: MethodInfo = MethodInfo {
get: Some(&TEST_API_METHOD), get: Some(&TEST_API_METHOD),
subdirs: Some(&phf_map!{"nodes" => &API3_NODES}), subdirs: Some(&phf_map!{"nodes" => &API3_NODES}),
..METHOD_INFO_DEFAULTS ..METHOD_INFO_DEFAULTS
}; };
macro_rules! http_error {
($status:ident, $msg:expr) => {{
let mut resp = Response::new(Body::from($msg));
*resp.status_mut() = StatusCode::$status;
return resp;
}}
}
fn hello_world(req: Request<Body>) -> Response<Body> { fn parse_query(query: &str) -> Value {
println!("PARSE QUERY {}", query);
// fixme: what about repeated parameters (arrays?)
let mut raw_param = HashMap::new();
for (k, v) in form_urlencoded::parse(query.as_bytes()) {
println!("QUERY PARAM {} value {}", k, v);
raw_param.insert(k, v);
}
println!("QUERY HASH {:?}", raw_param);
return json!(null);
}
fn handle_request(req: Request<Body>) -> Response<Body> {
let method = req.method(); let method = req.method();
let path = req.uri().path(); 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();
println!("REQUEST {} {}", method, path); println!("REQUEST {} {}", method, path);
println!("COMPO {:?}", components);
Response::new(Body::from("hello World!\n")) if comp_len >= 1 && components[0] == "api3" {
println!("GOT API REQUEST");
if comp_len >= 2 {
let format = components[1];
if format != "json" {
http_error!(NOT_FOUND, format!("Unsupported format '{}'\n", format))
}
if let Some(info) = find_method_info(&API_ROOT, &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,
_ => None,
};
let api_method = match api_method_opt {
Some(m) => m,
_ => http_error!(NOT_FOUND, format!("No such method '{} {}'\n", method, path)),
};
// handle auth
// extract param
let param = match query {
Some(data) => parse_query(data),
None => json!({}),
};
} else {
http_error!(NOT_FOUND, format!("No such path '{}'\n", path));
}
}
}
Response::new(Body::from("RETURN WEB GUI\n"))
} }
fn main() { fn main() {
@ -132,7 +201,7 @@ fn main() {
let new_svc = || { let new_svc = || {
// service_fn_ok converts our function into a `Service` // service_fn_ok converts our function into a `Service`
service_fn_ok(hello_world) service_fn_ok(handle_request)
}; };
let server = Server::bind(&addr) let server = Server::bind(&addr)