serv/
reply.rs

1use super::*;
2
3use async::*;
4use hyper::header::*;
5use std::convert::From;
6
7/// Oneshot-style reply which contains response or error.
8pub trait Reply<T, E>: serde::Serialize + From<Result<T, E>>
9where
10    T: serde::Serialize + 'static,
11    E: From<Error> + 'static,
12{
13    /// write reply body
14    fn reply(&self, status: hyper::StatusCode) -> HyperFuture {
15        let encoded = match serde_json::to_vec(&self) {
16            Ok(encoded) => encoded,
17            Err(e) => {
18                return Box::new(ok(resp_serv_err::<Error>(
19                    ErrorKind::EncodeJson(e).into(),
20                    hyper::StatusCode::OK,
21                )));
22            }
23        };
24
25        let header_len = HeaderValue::from_str(&encoded.len().to_string())
26            .expect("should not b an invalid utf-8");
27
28        Box::new(result(
29            Response::builder()
30                .status(status)
31                .header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
32                .header(CACHE_CONTROL, "no-cache, no-store, must-revalidate")
33                .header(CONTENT_TYPE, "application/json")
34                .header(CONTENT_LENGTH, header_len)
35                .body(encoded.into())
36                .or_else(|e| Ok(resp_serv_err(e, hyper::StatusCode::OK))),
37        ))
38    }
39
40    /// `serv_state` build `HyperService` with given function `F` and state `S`.
41    fn serv_state<F, S, Req>(state: S, f: F) -> HyperService
42    where
43        Self: 'static,
44        F: for<'a> Fn(&'a S, Req) -> Box<Future<Item = T, Error = E>> + 'static,
45        S: 'static,
46        Req: for<'de> serde::Deserialize<'de> + 'static,
47    {
48        let f = AsyncServiceFn::new(move |req| f(&state, req));
49        Box::new(async::AsyncServiceStateW::<_, Self>::new(f))
50    }
51
52    /// `service` builds `HyperService` with given function `F`.
53    fn serv<F, Req>(f: F) -> HyperService
54    where
55        Self: 'static,
56        F: Fn(Req) -> Box<Future<Item = T, Error = E>> + 'static,
57        Req: for<'de> serde::Deserialize<'de> + 'static,
58    {
59        let f = AsyncServiceFn::new(f);
60        Box::new(async::AsyncServiceStateW::<_, Self>::new(f))
61    }
62
63    /// `serv_state` builds `HyperService` with given function `F` and state `S`.
64    fn serv_state_sync<F, S, Req>(state: S, f: F) -> HyperService
65    where
66        Self: 'static,
67        F: for<'a> Fn(&'a S, Req) -> Result<T, E> + 'static,
68        S: 'static,
69        Req: for<'de> serde::Deserialize<'de> + 'static,
70    {
71        let f = async::AsyncServiceFn::new(move |req| Box::new(result(f(&state, req))));
72        Box::new(async::AsyncServiceStateW::<_, Self>::new(f))
73    }
74
75    /// `serv` build `HyperService` with given function `F`.
76    fn serv_sync<F, Req>(f: F) -> HyperService
77    where
78        Self: 'static,
79        F: Fn(Req) -> Result<T, E> + 'static,
80        Req: for<'de> serde::Deserialize<'de> + 'static,
81    {
82        let f = async::AsyncServiceFn::new(move |req| Box::new(result(f(req))));
83        Box::new(async::AsyncServiceStateW::<_, Self>::new(f))
84    }
85}
86
87#[derive(Serialize)]
88#[serde(tag = "status")]
89pub enum ServiceReply<T: serde::Serialize, E> {
90    #[serde(rename = "ok")]
91    Ok { result: T },
92    //TODO: reason
93    #[serde(rename = "error")]
94    Err {
95        reason: String,
96        #[serde(skip_serializing_if = "Option::is_none")]
97        msg: Option<String>,
98        #[serde(skip)]
99        _e: E,
100    },
101}
102
103impl<T, E> From<E> for ServiceReply<T, E>
104where
105    T: serde::Serialize,
106    E: Debug + std::error::Error,
107{
108    #[cfg(debug_assertions)]
109    fn from(e: E) -> ServiceReply<T, E> {
110        let reason = e.description().to_owned();
111        let msg = format!("{:?}", e);
112        ServiceReply::Err {
113            reason,
114            msg: Some(msg),
115            _e: e,
116        }
117    }
118
119    #[cfg(not(debug_assertions))]
120    fn from(e: E) -> ServiceReply<T, E> {
121        let reason = e.description().to_owned();
122        ServiceReply::Err {
123            reason,
124            msg: None,
125            _e: e,
126        }
127    }
128}
129
130impl<T, E> From<Result<T, E>> for ServiceReply<T, E>
131where
132    T: serde::Serialize,
133    E: Debug + std::error::Error,
134{
135    fn from(res: Result<T, E>) -> ServiceReply<T, E> {
136        match res {
137            Ok(resp) => ServiceReply::Ok { result: resp },
138            Err(e) => {
139                trace!("error: {:?}", e);
140                e.into()
141            }
142        }
143    }
144}
145
146impl<T, E> Reply<T, E> for ServiceReply<T, E>
147where
148    T: serde::Serialize + 'static,
149    E: From<Error> + Debug + std::error::Error + 'static,
150{}