3 use crate::api
::schema
::*;
4 use serde_json
::{Value}
;
5 use std
::collections
::HashMap
;
8 use hyper
::{Body, Response}
;
10 use hyper
::http
::request
::Parts
;
12 pub type BoxFut
= Box
<Future
<Item
= Response
<Body
>, Error
= failure
::Error
> + Send
>;
14 pub trait RpcEnvironment
{
16 fn set_result_attrib(&mut self, name
: &str, value
: Value
);
18 fn get_result_attrib(&self, name
: &str) -> Option
<&Value
>;
21 type ApiHandlerFn
= fn(Value
, &ApiMethod
, &mut dyn RpcEnvironment
) -> Result
<Value
, Error
>;
23 type ApiAsyncHandlerFn
= fn(Parts
, Body
, Value
, &ApiAsyncMethod
) -> Result
<BoxFut
, Error
>;
25 pub struct ApiMethod
{
26 pub parameters
: ObjectSchema
,
27 pub returns
: Arc
<Schema
>,
28 pub handler
: ApiHandlerFn
,
33 pub fn new(handler
: ApiHandlerFn
, parameters
: ObjectSchema
) -> Self {
37 returns
: Arc
::new(Schema
::Null
),
41 pub fn returns
<S
: Into
<Arc
<Schema
>>>(mut self, schema
: S
) -> Self {
43 self.returns
= schema
.into();
49 pub struct ApiAsyncMethod
{
50 pub parameters
: ObjectSchema
,
51 pub returns
: Arc
<Schema
>,
52 pub handler
: ApiAsyncHandlerFn
,
57 pub fn new(handler
: ApiAsyncHandlerFn
, parameters
: ObjectSchema
) -> Self {
61 returns
: Arc
::new(Schema
::Null
),
65 pub fn returns
<S
: Into
<Arc
<Schema
>>>(mut self, schema
: S
) -> Self {
67 self.returns
= schema
.into();
75 Hash(HashMap
<String
, Router
>),
76 MatchAll { router: Box<Router>, param_name: String }
,
79 pub enum MethodDefinition
{
82 Async(ApiAsyncMethod
),
86 pub get
: MethodDefinition
,
87 pub put
: MethodDefinition
,
88 pub post
: MethodDefinition
,
89 pub delete
: MethodDefinition
,
90 pub subroute
: SubRoute
,
95 pub fn new() -> Self {
97 get
: MethodDefinition
::None
,
98 put
: MethodDefinition
::None
,
99 post
: MethodDefinition
::None
,
100 delete
: MethodDefinition
::None
,
101 subroute
: SubRoute
::None
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());
109 match self.subroute
{
110 SubRoute
::Hash(ref mut map
) => {
111 map
.insert(subdir
.into(), router
);
113 _
=> panic
!("unexpected subroute type"),
118 pub fn subdirs(mut self, map
: HashMap
<String
, Router
>) -> Self {
119 self.subroute
= SubRoute
::Hash(map
);
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() }
;
127 panic
!("unexpected subroute type");
132 pub fn get(mut self, m
: ApiMethod
) -> Self {
133 self.get
= MethodDefinition
::Simple(m
);
137 pub fn put(mut self, m
: ApiMethod
) -> Self {
138 self.put
= MethodDefinition
::Simple(m
);
142 pub fn post(mut self, m
: ApiMethod
) -> Self {
143 self.post
= MethodDefinition
::Simple(m
);
147 pub fn upload(mut self, m
: ApiAsyncMethod
) -> Self {
148 self.post
= MethodDefinition
::Async(m
);
152 pub fn download(mut self, m
: ApiAsyncMethod
) -> Self {
153 self.get
= MethodDefinition
::Async(m
);
158 pub fn delete(mut self, m
: ApiMethod
) -> Self {
159 self.delete
= MethodDefinition
::Simple(m
);
163 pub fn find_route(&self, components
: &[&str], uri_param
: &mut HashMap
<String
, String
>) -> Option
<&Router
> {
165 if components
.len() == 0 { return Some(self); }
;
167 let (dir
, rest
) = (components
[0], &components
[1..]);
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
);
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
);