]> git.proxmox.com Git - proxmox-backup.git/blob - src/api/router.rs
api: pass RpcEnvirnment to api handlers
[proxmox-backup.git] / src / api / router.rs
1 use failure::*;
2
3 use crate::api::schema::*;
4 use serde_json::{Value};
5 use std::collections::HashMap;
6 use std::sync::Arc;
7
8 use hyper::{Body, Response};
9 use hyper::rt::Future;
10 use hyper::http::request::Parts;
11
12 pub type BoxFut = Box<Future<Item = Response<Body>, Error = failure::Error> + Send>;
13
14 pub trait RpcEnvironment {
15
16 fn set_result_attrib(&mut self, name: &str, value: Value);
17
18 fn get_result_attrib(&self, name: &str) -> Option<&Value>;
19 }
20
21 type ApiHandlerFn = fn(Value, &ApiMethod, &mut dyn RpcEnvironment) -> Result<Value, Error>;
22
23 type ApiAsyncHandlerFn = fn(Parts, Body, Value, &ApiAsyncMethod) -> Result<BoxFut, Error>;
24
25 pub struct ApiMethod {
26 pub parameters: ObjectSchema,
27 pub returns: Arc<Schema>,
28 pub handler: ApiHandlerFn,
29 }
30
31 impl ApiMethod {
32
33 pub fn new(handler: ApiHandlerFn, parameters: ObjectSchema) -> Self {
34 Self {
35 parameters,
36 handler,
37 returns: Arc::new(Schema::Null),
38 }
39 }
40
41 pub fn returns<S: Into<Arc<Schema>>>(mut self, schema: S) -> Self {
42
43 self.returns = schema.into();
44
45 self
46 }
47 }
48
49 pub struct ApiAsyncMethod {
50 pub parameters: ObjectSchema,
51 pub returns: Arc<Schema>,
52 pub handler: ApiAsyncHandlerFn,
53 }
54
55 impl ApiAsyncMethod {
56
57 pub fn new(handler: ApiAsyncHandlerFn, parameters: ObjectSchema) -> Self {
58 Self {
59 parameters,
60 handler,
61 returns: Arc::new(Schema::Null),
62 }
63 }
64
65 pub fn returns<S: Into<Arc<Schema>>>(mut self, schema: S) -> Self {
66
67 self.returns = schema.into();
68
69 self
70 }
71 }
72
73 pub enum SubRoute {
74 None,
75 Hash(HashMap<String, Router>),
76 MatchAll { router: Box<Router>, param_name: String },
77 }
78
79 pub enum MethodDefinition {
80 None,
81 Simple(ApiMethod),
82 Async(ApiAsyncMethod),
83 }
84
85 pub struct Router {
86 pub get: MethodDefinition,
87 pub put: MethodDefinition,
88 pub post: MethodDefinition,
89 pub delete: MethodDefinition,
90 pub subroute: SubRoute,
91 }
92
93 impl Router {
94
95 pub fn new() -> Self {
96 Self {
97 get: MethodDefinition::None,
98 put: MethodDefinition::None,
99 post: MethodDefinition::None,
100 delete: MethodDefinition::None,
101 subroute: SubRoute::None
102 }
103 }
104
105 pub fn subdir<S: Into<String>>(mut self, subdir: S, router: Router) -> Self {
106 if let SubRoute::None = self.subroute {
107 self.subroute = SubRoute::Hash(HashMap::new());
108 }
109 match self.subroute {
110 SubRoute::Hash(ref mut map) => {
111 map.insert(subdir.into(), router);
112 }
113 _ => panic!("unexpected subroute type"),
114 }
115 self
116 }
117
118 pub fn subdirs(mut self, map: HashMap<String, Router>) -> Self {
119 self.subroute = SubRoute::Hash(map);
120 self
121 }
122
123 pub fn match_all<S: Into<String>>(mut self, param_name: S, router: Router) -> Self {
124 if let SubRoute::None = self.subroute {
125 self.subroute = SubRoute::MatchAll { router: Box::new(router), param_name: param_name.into() };
126 } else {
127 panic!("unexpected subroute type");
128 }
129 self
130 }
131
132 pub fn get(mut self, m: ApiMethod) -> Self {
133 self.get = MethodDefinition::Simple(m);
134 self
135 }
136
137 pub fn put(mut self, m: ApiMethod) -> Self {
138 self.put = MethodDefinition::Simple(m);
139 self
140 }
141
142 pub fn post(mut self, m: ApiMethod) -> Self {
143 self.post = MethodDefinition::Simple(m);
144 self
145 }
146
147 pub fn upload(mut self, m: ApiAsyncMethod) -> Self {
148 self.post = MethodDefinition::Async(m);
149 self
150 }
151
152 pub fn download(mut self, m: ApiAsyncMethod) -> Self {
153 self.get = MethodDefinition::Async(m);
154 self
155 }
156
157
158 pub fn delete(mut self, m: ApiMethod) -> Self {
159 self.delete = MethodDefinition::Simple(m);
160 self
161 }
162
163 pub fn find_route(&self, components: &[&str], uri_param: &mut HashMap<String, String>) -> Option<&Router> {
164
165 if components.len() == 0 { return Some(self); };
166
167 let (dir, rest) = (components[0], &components[1..]);
168
169 match self.subroute {
170 SubRoute::None => {},
171 SubRoute::Hash(ref dirmap) => {
172 if let Some(ref router) = dirmap.get(dir) {
173 println!("FOUND SUBDIR {}", dir);
174 return router.find_route(rest, uri_param);
175 }
176 }
177 SubRoute::MatchAll { ref router, ref param_name } => {
178 println!("URI PARAM {} = {}", param_name, dir); // fixme: store somewhere
179 uri_param.insert(param_name.clone(), dir.into());
180 return router.find_route(rest, uri_param);
181 },
182 }
183
184 None
185 }
186 }