proxmox-backup/src/api/router.rs

187 lines
4.7 KiB
Rust
Raw Normal View History

2018-11-15 16:07:55 +00:00
use failure::*;
use crate::api::schema::*;
use serde_json::{Value};
use std::collections::HashMap;
2018-12-06 09:41:57 +00:00
use std::sync::Arc;
2018-11-15 16:07:55 +00:00
use hyper::{Body, Response};
use hyper::rt::Future;
use hyper::http::request::Parts;
pub type BoxFut = Box<Future<Item = Response<Body>, Error = failure::Error> + Send>;
pub trait RpcEnvironment {
fn set_result_attrib(&mut self, name: &str, value: Value);
fn get_result_attrib(&self, name: &str) -> Option<&Value>;
}
type ApiHandlerFn = fn(Value, &ApiMethod, &mut dyn RpcEnvironment) -> Result<Value, Error>;
2018-12-06 09:23:45 +00:00
2019-01-27 09:18:52 +00:00
type ApiAsyncHandlerFn = fn(Parts, Body, Value, &ApiAsyncMethod, &mut dyn RpcEnvironment) -> Result<BoxFut, Error>;
2018-11-15 16:07:55 +00:00
pub struct ApiMethod {
pub parameters: ObjectSchema,
2018-12-06 09:41:57 +00:00
pub returns: Arc<Schema>,
2018-12-06 09:23:45 +00:00
pub handler: ApiHandlerFn,
}
impl ApiMethod {
pub fn new(handler: ApiHandlerFn, parameters: ObjectSchema) -> Self {
Self {
parameters,
handler,
2018-12-06 09:41:57 +00:00
returns: Arc::new(Schema::Null),
2018-12-06 09:23:45 +00:00
}
}
2018-12-06 09:41:57 +00:00
pub fn returns<S: Into<Arc<Schema>>>(mut self, schema: S) -> Self {
self.returns = schema.into();
self
}
}
pub struct ApiAsyncMethod {
pub parameters: ObjectSchema,
pub returns: Arc<Schema>,
pub handler: ApiAsyncHandlerFn,
}
impl ApiAsyncMethod {
pub fn new(handler: ApiAsyncHandlerFn, parameters: ObjectSchema) -> Self {
Self {
parameters,
handler,
returns: Arc::new(Schema::Null),
}
}
pub fn returns<S: Into<Arc<Schema>>>(mut self, schema: S) -> Self {
2018-12-06 09:41:57 +00:00
self.returns = schema.into();
self
}
2018-11-15 16:07:55 +00:00
}
pub enum SubRoute {
None,
Hash(HashMap<String, Router>),
MatchAll { router: Box<Router>, param_name: String },
}
pub enum MethodDefinition {
None,
Simple(ApiMethod),
Async(ApiAsyncMethod),
}
2018-11-15 16:07:55 +00:00
pub struct Router {
pub get: MethodDefinition,
pub put: MethodDefinition,
pub post: MethodDefinition,
pub delete: MethodDefinition,
2018-11-15 16:07:55 +00:00
pub subroute: SubRoute,
}
impl Router {
pub fn new() -> Self {
Self {
get: MethodDefinition::None,
put: MethodDefinition::None,
post: MethodDefinition::None,
delete: MethodDefinition::None,
2018-11-15 16:07:55 +00:00
subroute: SubRoute::None
}
}
2018-12-06 09:23:45 +00:00
pub fn subdir<S: Into<String>>(mut self, subdir: S, router: Router) -> Self {
if let SubRoute::None = self.subroute {
self.subroute = SubRoute::Hash(HashMap::new());
}
match self.subroute {
SubRoute::Hash(ref mut map) => {
map.insert(subdir.into(), router);
}
_ => panic!("unexpected subroute type"),
}
self
}
2018-11-15 16:07:55 +00:00
pub fn subdirs(mut self, map: HashMap<String, Router>) -> Self {
self.subroute = SubRoute::Hash(map);
self
}
2018-12-06 09:23:45 +00:00
pub fn match_all<S: Into<String>>(mut self, param_name: S, router: Router) -> Self {
if let SubRoute::None = self.subroute {
self.subroute = SubRoute::MatchAll { router: Box::new(router), param_name: param_name.into() };
} else {
panic!("unexpected subroute type");
}
2018-11-15 16:07:55 +00:00
self
}
pub fn get(mut self, m: ApiMethod) -> Self {
self.get = MethodDefinition::Simple(m);
2018-11-15 16:07:55 +00:00
self
}
2018-12-06 09:23:45 +00:00
pub fn put(mut self, m: ApiMethod) -> Self {
self.put = MethodDefinition::Simple(m);
self
}
2018-12-06 09:23:45 +00:00
pub fn post(mut self, m: ApiMethod) -> Self {
self.post = MethodDefinition::Simple(m);
self
}
pub fn upload(mut self, m: ApiAsyncMethod) -> Self {
self.post = MethodDefinition::Async(m);
self
}
2018-12-06 09:23:45 +00:00
pub fn download(mut self, m: ApiAsyncMethod) -> Self {
self.get = MethodDefinition::Async(m);
self
}
pub fn delete(mut self, m: ApiMethod) -> Self {
self.delete = MethodDefinition::Simple(m);
self
}
2018-11-15 16:07:55 +00:00
2018-11-16 08:15:33 +00:00
pub fn find_route(&self, components: &[&str], uri_param: &mut HashMap<String, String>) -> Option<&Router> {
2018-11-15 16:07:55 +00:00
if components.len() == 0 { return Some(self); };
let (dir, rest) = (components[0], &components[1..]);
match self.subroute {
SubRoute::None => {},
SubRoute::Hash(ref dirmap) => {
if let Some(ref router) = dirmap.get(dir) {
println!("FOUND SUBDIR {}", dir);
2018-11-16 08:15:33 +00:00
return router.find_route(rest, uri_param);
2018-11-15 16:07:55 +00:00
}
}
SubRoute::MatchAll { ref router, ref param_name } => {
println!("URI PARAM {} = {}", param_name, dir); // fixme: store somewhere
2018-11-16 08:15:33 +00:00
uri_param.insert(param_name.clone(), dir.into());
return router.find_route(rest, uri_param);
2018-11-15 16:07:55 +00:00
},
}
None
}
}