api/router.rs: allow different types of api methods
Added a prototype for file/backup uploads.
This commit is contained in:
parent
b41d1aab8c
commit
7e21da6e23
|
@ -21,21 +21,18 @@ impl ApiConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_method(&self, components: &[&str], method: Method, uri_param: &mut HashMap<String, String>) -> Option<&'static ApiMethod> {
|
pub fn find_method(&self, components: &[&str], method: Method, uri_param: &mut HashMap<String, String>) -> &'static MethodDefinition {
|
||||||
|
|
||||||
if let Some(info) = self.router.find_route(components, uri_param) {
|
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::GET => &info.get,
|
||||||
Method::PUT => &info.put,
|
Method::PUT => &info.put,
|
||||||
Method::POST => &info.post,
|
Method::POST => &info.post,
|
||||||
Method::DELETE => &info.delete,
|
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 {
|
pub fn find_alias(&self, components: &[&str]) -> PathBuf {
|
||||||
|
|
|
@ -5,8 +5,15 @@ use serde_json::{Value};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use hyper::{Body, Response};
|
||||||
|
use hyper::rt::Future;
|
||||||
|
|
||||||
|
pub type BoxFut = Box<Future<Item = Response<Body>, Error = failure::Error> + Send>;
|
||||||
|
|
||||||
type ApiHandlerFn = fn(Value, &ApiMethod) -> Result<Value, Error>;
|
type ApiHandlerFn = fn(Value, &ApiMethod) -> Result<Value, Error>;
|
||||||
|
|
||||||
|
type ApiUploadHandlerFn = fn(hyper::Body, Value, &ApiUploadMethod) -> BoxFut;
|
||||||
|
|
||||||
pub struct ApiMethod {
|
pub struct ApiMethod {
|
||||||
pub parameters: ObjectSchema,
|
pub parameters: ObjectSchema,
|
||||||
pub returns: Arc<Schema>,
|
pub returns: Arc<Schema>,
|
||||||
|
@ -29,7 +36,30 @@ impl ApiMethod {
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ApiUploadMethod {
|
||||||
|
pub parameters: ObjectSchema,
|
||||||
|
pub returns: Arc<Schema>,
|
||||||
|
pub handler: ApiUploadHandlerFn,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApiUploadMethod {
|
||||||
|
|
||||||
|
pub fn new(handler: ApiUploadHandlerFn, parameters: ObjectSchema) -> Self {
|
||||||
|
Self {
|
||||||
|
parameters,
|
||||||
|
handler,
|
||||||
|
returns: Arc::new(Schema::Null),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn returns<S: Into<Arc<Schema>>>(mut self, schema: S) -> Self {
|
||||||
|
|
||||||
|
self.returns = schema.into();
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum SubRoute {
|
pub enum SubRoute {
|
||||||
|
@ -38,11 +68,17 @@ pub enum SubRoute {
|
||||||
MatchAll { router: Box<Router>, param_name: String },
|
MatchAll { router: Box<Router>, param_name: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum MethodDefinition {
|
||||||
|
None,
|
||||||
|
Simple(ApiMethod),
|
||||||
|
Upload(ApiUploadMethod),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Router {
|
pub struct Router {
|
||||||
pub get: Option<ApiMethod>,
|
pub get: MethodDefinition,
|
||||||
pub put: Option<ApiMethod>,
|
pub put: MethodDefinition,
|
||||||
pub post: Option<ApiMethod>,
|
pub post: MethodDefinition,
|
||||||
pub delete: Option<ApiMethod>,
|
pub delete: MethodDefinition,
|
||||||
pub subroute: SubRoute,
|
pub subroute: SubRoute,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,10 +86,10 @@ impl Router {
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
get: None,
|
get: MethodDefinition::None,
|
||||||
put: None,
|
put: MethodDefinition::None,
|
||||||
post: None,
|
post: MethodDefinition::None,
|
||||||
delete: None,
|
delete: MethodDefinition::None,
|
||||||
subroute: SubRoute::None
|
subroute: SubRoute::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,22 +122,27 @@ impl Router {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(mut self, m: ApiMethod) -> Self {
|
pub fn get(mut self, m: ApiMethod) -> Self {
|
||||||
self.get = Some(m);
|
self.get = MethodDefinition::Simple(m);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put(mut self, m: ApiMethod) -> Self {
|
pub fn put(mut self, m: ApiMethod) -> Self {
|
||||||
self.put = Some(m);
|
self.put = MethodDefinition::Simple(m);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn post(mut self, m: ApiMethod) -> 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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(mut self, m: ApiMethod) -> Self {
|
pub fn delete(mut self, m: ApiMethod) -> Self {
|
||||||
self.delete = Some(m);
|
self.delete = MethodDefinition::Simple(m);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,12 @@ use failure::*;
|
||||||
|
|
||||||
use crate::api::schema::*;
|
use crate::api::schema::*;
|
||||||
use crate::api::router::*;
|
use crate::api::router::*;
|
||||||
|
use crate::server::rest::*;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
|
use hyper::StatusCode;
|
||||||
|
use hyper::rt::{Future, Stream};
|
||||||
|
|
||||||
use crate::config::datastore;
|
use crate::config::datastore;
|
||||||
|
|
||||||
use crate::backup::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<Value, Error> {
|
fn get_datastore_list(_param: Value, _info: &ApiMethod) -> Result<Value, Error> {
|
||||||
|
|
||||||
let config = datastore::config()?;
|
let config = datastore::config()?;
|
||||||
|
@ -67,12 +105,13 @@ pub fn router() -> Router {
|
||||||
ObjectSchema::new("Directory index.")
|
ObjectSchema::new("Directory index.")
|
||||||
.required("name", StringSchema::new("Datastore name.")))
|
.required("name", StringSchema::new("Datastore name.")))
|
||||||
)
|
)
|
||||||
|
.upload(api_method_upload_catar())
|
||||||
.subdir(
|
.subdir(
|
||||||
"gc",
|
"gc",
|
||||||
Router::new()
|
Router::new()
|
||||||
.get(api_method_garbage_collection_status())
|
.get(api_method_garbage_collection_status())
|
||||||
.post(api_method_start_garbage_collection()));
|
.post(api_method_start_garbage_collection()));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let route = Router::new()
|
let route = Router::new()
|
||||||
|
|
|
@ -21,9 +21,11 @@ pub mod api {
|
||||||
pub mod config;
|
pub mod config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
pub mod server {
|
pub mod server {
|
||||||
|
|
||||||
pub mod formatter;
|
pub mod formatter;
|
||||||
|
#[macro_use]
|
||||||
pub mod rest;
|
pub mod rest;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,8 +82,6 @@ impl Service for ApiService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type BoxFut = Box<Future<Item = Response<Body>, Error = failure::Error> + Send>;
|
|
||||||
|
|
||||||
#[derive(Debug, Fail)]
|
#[derive(Debug, Fail)]
|
||||||
pub struct HttpError {
|
pub struct HttpError {
|
||||||
pub code: StatusCode,
|
pub code: StatusCode,
|
||||||
|
@ -180,6 +178,31 @@ fn handle_sync_api_request(
|
||||||
Box::new(resp)
|
Box::new(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_upload_api_request(
|
||||||
|
info: &'static ApiUploadMethod,
|
||||||
|
formatter: &'static OutputFormatter,
|
||||||
|
parts: Parts,
|
||||||
|
req_body: Body,
|
||||||
|
uri_param: HashMap<String, String>,
|
||||||
|
) -> 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 {
|
fn get_index() -> BoxFut {
|
||||||
|
|
||||||
let nodename = "unknown";
|
let nodename = "unknown";
|
||||||
|
@ -362,9 +385,15 @@ pub fn handle_request(api: Arc<ApiConfig>, req: Request<Body>) -> BoxFut {
|
||||||
|
|
||||||
let mut uri_param = HashMap::new();
|
let mut uri_param = HashMap::new();
|
||||||
|
|
||||||
if let Some(api_method) = api.find_method(&components[2..], method, &mut uri_param) {
|
// fixme: handle auth
|
||||||
// fixme: handle auth
|
match api.find_method(&components[2..], method, &mut uri_param) {
|
||||||
return handle_sync_api_request(api_method, formatter, parts, body, 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 {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue