From 1a53be1443c2b89ab0c59f2a7e98380fe35c8996 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Wed, 14 Nov 2018 13:22:33 +0100 Subject: [PATCH] factor out server code into api_server.rs --- src/api_info.rs | 4 +-- src/api_server.rs | 73 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 ++ src/main.rs | 87 ++++++++++++----------------------------------- 4 files changed, 99 insertions(+), 67 deletions(-) create mode 100644 src/api_server.rs diff --git a/src/api_info.rs b/src/api_info.rs index cc9f2b38..ebed6ddf 100644 --- a/src/api_info.rs +++ b/src/api_info.rs @@ -59,7 +59,7 @@ impl MethodInfo { self } - pub fn find_method(&self, components: &[&str]) -> Option<&MethodInfo> { + pub fn find_route(&self, components: &[&str]) -> Option<&MethodInfo> { if components.len() == 0 { return Some(self); }; @@ -67,7 +67,7 @@ impl MethodInfo { if let Some(ref dirmap) = self.subdirs { if let Some(ref info) = dirmap.get(dir) { - return info.find_method(rest); + return info.find_route(rest); } } diff --git a/src/api_server.rs b/src/api_server.rs new file mode 100644 index 00000000..d6e98788 --- /dev/null +++ b/src/api_server.rs @@ -0,0 +1,73 @@ +use std::collections::HashMap; +use std::path::{PathBuf}; +use crate::api_info::*; +use crate::json_schema::*; + +use futures::future::{self, Either}; + +use tokio::fs::File; +use tokio_codec; + + +use hyper::http::request::Parts; +use hyper::{Method, Body, Request, Response, Server, StatusCode}; +use hyper::rt::{Future, Stream}; +use hyper::service::{service_fn, NewService}; +use hyper::header; + +pub struct ApiServer { + basedir: PathBuf, + router: &'static MethodInfo, + aliases: HashMap, +} + +impl ApiServer { + + pub fn new>(basedir: B, router: &'static MethodInfo) -> Self { + ApiServer { + basedir: basedir.into(), + router: router, + aliases: HashMap::new(), + } + } + + pub fn find_method(&self, components: &[&str], method: Method) -> Option<&'static ApiMethod> { + + if let Some(info) = self.router.find_route(components) { + println!("FOUND INFO"); + let opt_api_method = match method { + Method::GET => &info.get, + Method::PUT => &info.put, + Method::POST => &info.post, + Method::DELETE => &info.delete, + _ => &None, + }; + if let Some(api_method) = opt_api_method { + return Some(&api_method); + } + } + None + } + + pub fn find_alias(&self, components: &[&str]) -> PathBuf { + + let mut prefix = String::new(); + let mut filename = self.basedir.clone(); + let comp_len = components.len(); + if comp_len >= 1 { + prefix.push_str(components[0]); + if let Some(subdir) = self.aliases.get(&prefix) { + filename.push(subdir); + for i in 1..comp_len { filename.push(components[i]) } + } + } + filename + } + + pub fn add_alias(&mut self, alias: S, path: P) + where S: Into, + P: Into, + { + self.aliases.insert(alias.into(), path.into()); + } +} diff --git a/src/lib.rs b/src/lib.rs index 0391a950..1310d49a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,5 +6,7 @@ pub mod json_schema; #[macro_use] pub mod api_info; +pub mod api_server; + pub mod api3; diff --git a/src/main.rs b/src/main.rs index 73cd1c8d..0af3dd22 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ extern crate apitest; use failure::*; use std::sync::Arc; -use std::collections::HashMap; +//use std::collections::HashMap; //use std::io; //use std::fs; use std::path::{PathBuf}; @@ -13,6 +13,7 @@ use lazy_static::lazy_static; //use apitest::json_schema::*; use apitest::api_info::*; use apitest::json_schema::*; +use apitest::api_server::*; //use serde_derive::{Serialize, Deserialize}; use serde_json::{json, Value}; @@ -26,7 +27,7 @@ use tokio_codec; //use hyper::body::Payload; use hyper::http::request::Parts; -use hyper::{Method, Body, Request, Response, Server, StatusCode}; +use hyper::{Body, Request, Response, Server, StatusCode}; use hyper::rt::{Future, Stream}; use hyper::service::service_fn; use hyper::header; @@ -214,7 +215,7 @@ fn handle_static_file_download(filename: PathBuf) -> BoxFut { return Box::new(response); } -fn handle_request(api: &ApiServer, req: Request) -> BoxFut { +fn handle_request<'a>(api: &'a ApiServer, req: Request) -> BoxFut { let (parts, body) = req.into_parts(); @@ -252,38 +253,15 @@ fn handle_request(api: &ApiServer, req: Request) -> BoxFut { http_error_future!(BAD_REQUEST, format!("Unsupported output format '{}'.", format)) } - if let Some(info) = api.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, - _ => &None, - }; - let api_method = match api_method_opt { - Some(m) => m, - _ => http_error_future!(NOT_FOUND, format!("No such method '{}'.", method)), - }; - + if let Some(api_method) = api.find_method(&components[2..], method) { // fixme: handle auth - - //return handle_sync_api_request(api_method, parts, body); return handle_async_api_request(api_method, parts, body); } } } else { // not Auth for accessing files! - let mut prefix = String::new(); - let mut filename = PathBuf::from("/var/www"); // fixme - if comp_len >= 1 { - prefix.push_str(components[0]); - if let Some(subdir) = api.aliases.get(&prefix) { - filename.push(subdir); - for i in 1..comp_len { filename.push(components[i]) } - } - } + let filename = api.find_alias(&components); return handle_static_file_download(filename); } @@ -292,52 +270,31 @@ fn handle_request(api: &ApiServer, req: Request) -> BoxFut { //Box::new(ok(Response::new(Body::from("RETURN WEB GUI\n")))) } -// add default dirs which includes jquery and bootstrap -// my $base = '/usr/share/libpve-http-server-perl'; -// add_dirs($self->{dirs}, '/css/' => "$base/css/"); -// add_dirs($self->{dirs}, '/js/' => "$base/js/"); -// add_dirs($self->{dirs}, '/fonts/' => "$base/fonts/"); - - -fn initialize_directory_aliases() -> HashMap { - - let mut basedirs: HashMap = HashMap::new(); - - let mut add_directory_alias = |name, path| { - basedirs.insert(String::from(name), PathBuf::from(path)); - }; - - add_directory_alias("novnc", "/usr/share/novnc-pve"); - add_directory_alias("extjs", "/usr/share/javascript/extjs"); - add_directory_alias("fontawesome", "/usr/share/fonts-font-awesome"); - add_directory_alias("xtermjs", "/usr/share/pve-xtermjs"); - add_directory_alias("widgettoolkit", "/usr/share/javascript/proxmox-widget-toolkit"); - - basedirs -} - -struct ApiServer { - basedir: PathBuf, - router: &'static MethodInfo, - aliases: &'static HashMap, -} - fn main() { println!("Fast Static Type Definitions 1"); let addr = ([127, 0, 0, 1], 8007).into(); lazy_static!{ - static ref ALIASES: HashMap = initialize_directory_aliases(); - static ref ROUTER: MethodInfo = apitest::api3::router(); + static ref ROUTER: MethodInfo = apitest::api3::router(); } - let api_server = Arc::new(ApiServer { - basedir: "/var/www". into(), - router: &ROUTER, - aliases: &ALIASES, - }); + let mut api_server = ApiServer::new("/var/www", &ROUTER); + // add default dirs which includes jquery and bootstrap + // my $base = '/usr/share/libpve-http-server-perl'; + // add_dirs($self->{dirs}, '/css/' => "$base/css/"); + // add_dirs($self->{dirs}, '/js/' => "$base/js/"); + // add_dirs($self->{dirs}, '/fonts/' => "$base/fonts/"); + api_server.add_alias("novnc", "/usr/share/novnc-pve"); + api_server.add_alias("extjs", "/usr/share/javascript/extjs"); + api_server.add_alias("fontawesome", "/usr/share/fonts-font-awesome"); + api_server.add_alias("xtermjs", "/usr/share/pve-xtermjs"); + api_server.add_alias("widgettoolkit", "/usr/share/javascript/proxmox-widget-toolkit"); + + + let api_server = Arc::new(api_server); + let new_svc = move || { let api = api_server.clone();