diff --git a/src/api/config.rs b/src/api/config.rs index b0908421..b395668b 100644 --- a/src/api/config.rs +++ b/src/api/config.rs @@ -21,21 +21,18 @@ impl ApiConfig { } } - pub fn find_method(&self, components: &[&str], method: Method, uri_param: &mut HashMap) -> Option<&'static ApiMethod> { + pub fn find_method(&self, components: &[&str], method: Method, uri_param: &mut HashMap) -> &'static MethodDefinition { if let Some(info) = self.router.find_route(components, uri_param) { - let opt_api_method = match method { + return match method { Method::GET => &info.get, Method::PUT => &info.put, Method::POST => &info.post, Method::DELETE => &info.delete, - _ => &None, + _ => &MethodDefinition::None, }; - if let Some(api_method) = opt_api_method { - return Some(&api_method); - } } - None + &MethodDefinition::None } pub fn find_alias(&self, components: &[&str]) -> PathBuf { diff --git a/src/api/router.rs b/src/api/router.rs index e9251b89..03d5c732 100644 --- a/src/api/router.rs +++ b/src/api/router.rs @@ -5,8 +5,15 @@ use serde_json::{Value}; use std::collections::HashMap; use std::sync::Arc; +use hyper::{Body, Response}; +use hyper::rt::Future; + +pub type BoxFut = Box, Error = failure::Error> + Send>; + type ApiHandlerFn = fn(Value, &ApiMethod) -> Result; +type ApiUploadHandlerFn = fn(hyper::Body, Value, &ApiUploadMethod) -> BoxFut; + pub struct ApiMethod { pub parameters: ObjectSchema, pub returns: Arc, @@ -29,7 +36,30 @@ impl ApiMethod { self } +} +pub struct ApiUploadMethod { + pub parameters: ObjectSchema, + pub returns: Arc, + pub handler: ApiUploadHandlerFn, +} + +impl ApiUploadMethod { + + pub fn new(handler: ApiUploadHandlerFn, parameters: ObjectSchema) -> Self { + Self { + parameters, + handler, + returns: Arc::new(Schema::Null), + } + } + + pub fn returns>>(mut self, schema: S) -> Self { + + self.returns = schema.into(); + + self + } } pub enum SubRoute { @@ -38,11 +68,17 @@ pub enum SubRoute { MatchAll { router: Box, param_name: String }, } +pub enum MethodDefinition { + None, + Simple(ApiMethod), + Upload(ApiUploadMethod), +} + pub struct Router { - pub get: Option, - pub put: Option, - pub post: Option, - pub delete: Option, + pub get: MethodDefinition, + pub put: MethodDefinition, + pub post: MethodDefinition, + pub delete: MethodDefinition, pub subroute: SubRoute, } @@ -50,10 +86,10 @@ impl Router { pub fn new() -> Self { Self { - get: None, - put: None, - post: None, - delete: None, + get: MethodDefinition::None, + put: MethodDefinition::None, + post: MethodDefinition::None, + delete: MethodDefinition::None, subroute: SubRoute::None } } @@ -86,22 +122,27 @@ impl Router { } pub fn get(mut self, m: ApiMethod) -> Self { - self.get = Some(m); + self.get = MethodDefinition::Simple(m); self } pub fn put(mut self, m: ApiMethod) -> Self { - self.put = Some(m); + self.put = MethodDefinition::Simple(m); self } pub fn post(mut self, m: ApiMethod) -> Self { - self.post = Some(m); + self.post = MethodDefinition::Simple(m); + self + } + + pub fn upload(mut self, m: ApiUploadMethod) -> Self { + self.post = MethodDefinition::Upload(m); self } pub fn delete(mut self, m: ApiMethod) -> Self { - self.delete = Some(m); + self.delete = MethodDefinition::Simple(m); self } diff --git a/src/api3/admin/datastore.rs b/src/api3/admin/datastore.rs index 959eac3e..a3c865c1 100644 --- a/src/api3/admin/datastore.rs +++ b/src/api3/admin/datastore.rs @@ -2,8 +2,12 @@ use failure::*; use crate::api::schema::*; use crate::api::router::*; +use crate::server::rest::*; use serde_json::{json, Value}; +use hyper::StatusCode; +use hyper::rt::{Future, Stream}; + use crate::config::datastore; use crate::backup::datastore::*; @@ -48,6 +52,40 @@ pub fn api_method_garbage_collection_status() -> ApiMethod { ) } +fn upload_catar(req_body: hyper::Body, param: Value, _info: &ApiUploadMethod) -> BoxFut { + + let name = param["name"].as_str().unwrap(); + + println!("Upload .catar to {}", name); + + let resp = req_body + .map_err(|err| http_err!(BAD_REQUEST, format!("Promlems reading request body: {}", err))) + .for_each(|chunk| { + println!("UPLOAD Chunk {}", chunk.len()); + Ok(()) + }) + .and_then(|()| { + println!("UPLOAD DATA Sucessful"); + + let response = http::Response::builder() + .status(200) + .body(hyper::Body::empty()) + .unwrap(); + + Ok(response) + }); + + Box::new(resp) +} + +fn api_method_upload_catar() -> ApiUploadMethod { + ApiUploadMethod::new( + upload_catar, + ObjectSchema::new("Upload .catar backup file.") + .required("name", StringSchema::new("Datastore name.")) + ) +} + fn get_datastore_list(_param: Value, _info: &ApiMethod) -> Result { let config = datastore::config()?; @@ -67,12 +105,13 @@ pub fn router() -> Router { ObjectSchema::new("Directory index.") .required("name", StringSchema::new("Datastore name."))) ) + .upload(api_method_upload_catar()) .subdir( "gc", Router::new() .get(api_method_garbage_collection_status()) .post(api_method_start_garbage_collection())); - + let route = Router::new() diff --git a/src/lib.rs b/src/lib.rs index ac4f7d97..af2b3870 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,9 +21,11 @@ pub mod api { pub mod config; } +#[macro_use] pub mod server { pub mod formatter; + #[macro_use] pub mod rest; } diff --git a/src/server/rest.rs b/src/server/rest.rs index d9475d1a..5d3f23c3 100644 --- a/src/server/rest.rs +++ b/src/server/rest.rs @@ -82,8 +82,6 @@ impl Service for ApiService { } } -type BoxFut = Box, Error = failure::Error> + Send>; - #[derive(Debug, Fail)] pub struct HttpError { pub code: StatusCode, @@ -180,6 +178,31 @@ fn handle_sync_api_request( Box::new(resp) } +fn handle_upload_api_request( + info: &'static ApiUploadMethod, + formatter: &'static OutputFormatter, + parts: Parts, + req_body: Body, + uri_param: HashMap, +) -> BoxFut +{ + // fixme: convert parameters to Json + let mut param_list: Vec<(String, String)> = vec![]; + + for (k, v) in uri_param { + param_list.push((k.clone(), v.clone())); + } + + let params = match parse_parameter_strings(¶m_list, &info.parameters, true) { + Ok(v) => v, + Err(err) => { + return Box::new(future::err(err.into())); + } + }; + + (info.handler)(req_body, params, info) +} + fn get_index() -> BoxFut { let nodename = "unknown"; @@ -362,9 +385,15 @@ pub fn handle_request(api: Arc, req: Request) -> BoxFut { let mut uri_param = HashMap::new(); - if let Some(api_method) = api.find_method(&components[2..], method, &mut uri_param) { - // fixme: handle auth - return handle_sync_api_request(api_method, formatter, parts, body, uri_param); + // fixme: handle auth + match api.find_method(&components[2..], method, &mut uri_param) { + MethodDefinition::None => {} + MethodDefinition::Simple(api_method) => { + return handle_sync_api_request(api_method, formatter, parts, body, uri_param); + } + MethodDefinition::Upload(upload_method) => { + return handle_upload_api_request(upload_method, formatter, parts, body, uri_param); + } } } } else {