eva_common/
hyper_tools.rs1use crate::value::{to_value, Value};
2use crate::ErrorKind;
3use hyper::{http, Body, HeaderMap, Response, StatusCode};
4use serde::Serialize;
5use std::error::Error;
6
7pub const DEFAULT_MIME: &str = "application/octet-stream";
8
9#[macro_export]
10macro_rules! hyper_response {
11 ($code: expr, $message: expr) => {
12 hyper::Response::builder()
13 .status($code)
14 .body(Body::from($message))
15 };
16 ($code: expr) => {
17 hyper::Response::builder().status($code).body(Body::empty())
18 };
19}
20
21pub type HResult = std::result::Result<HContent, crate::Error>;
22
23pub trait HResultX {
24 fn into_hyper_response(self) -> Result<Response<Body>, http::Error>;
25}
26
27impl HResultX for HResult {
28 fn into_hyper_response(self) -> Result<Response<Body>, http::Error> {
29 match self {
30 Ok(resp) => match resp {
31 HContent::Data(v, mime, header_map) => {
32 let mut r = Response::builder();
33 if let Some(mt) = mime {
34 if mt.starts_with("text/") {
35 r = r.header(
36 hyper::header::CONTENT_TYPE,
37 &format!("{};charset=utf-8", mt),
38 );
39 } else {
40 r = r.header(hyper::header::CONTENT_TYPE, mt);
41 }
42 } else {
43 r = r.header(hyper::header::CONTENT_TYPE, DEFAULT_MIME);
44 }
45 let mut result = r.status(StatusCode::OK).body(Body::from(v))?;
46 if let Some(h) = header_map {
47 result.headers_mut().extend(h);
48 }
49 Ok(result)
50 }
51 HContent::Value(val) => match serde_json::to_vec(&val) {
52 Ok(v) => Response::builder()
53 .header(hyper::header::CONTENT_TYPE, "application/json")
54 .status(StatusCode::OK)
55 .body(Body::from(v)),
56 Err(e) => {
57 hyper_response!(StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
58 }
59 },
60 HContent::Redirect(l) => Response::builder()
61 .status(StatusCode::MOVED_PERMANENTLY)
62 .header(hyper::header::LOCATION, l)
63 .body(Body::empty()),
64 HContent::HyperResult(r) => r,
65 },
66 Err(e) if e.kind() == ErrorKind::ResourceNotFound => {
67 hyper_response!(StatusCode::NOT_FOUND, e.to_string())
68 }
69 Err(e) if e.kind() == ErrorKind::AccessDenied => {
70 hyper_response!(StatusCode::FORBIDDEN, e.to_string())
71 }
72 Err(e) if e.kind() == ErrorKind::InvalidParameter => {
73 hyper_response!(StatusCode::BAD_REQUEST, e.to_string())
74 }
75 Err(e) => {
76 hyper_response!(StatusCode::INTERNAL_SERVER_ERROR, e.to_string())
77 }
78 }
79 }
80}
81
82pub enum HContent {
83 Data(Vec<u8>, Option<&'static str>, Option<HeaderMap>),
84 Value(Value),
85 Redirect(String),
86 HyperResult(Result<Response<Body>, http::Error>),
87}
88
89impl HContent {
90 pub fn ok() -> Self {
94 #[derive(Serialize)]
95 struct OK {
96 ok: bool,
97 }
98 HContent::Value(to_value(OK { ok: true }).unwrap())
99 }
100 pub fn not_ok() -> Self {
104 #[derive(Serialize)]
105 struct OK {
106 ok: bool,
107 }
108 HContent::Value(to_value(OK { ok: false }).unwrap())
109 }
110}
111
112impl From<hyper_static::serve::Error> for crate::Error {
113 fn from(e: hyper_static::serve::Error) -> Self {
114 match e.kind() {
115 hyper_static::serve::ErrorKind::Internal => {
116 Self::newc(ErrorKind::FunctionFailed, e.source())
117 }
118 hyper_static::serve::ErrorKind::NotFound => {
119 Self::newc(ErrorKind::ResourceNotFound, e.source())
120 }
121 hyper_static::serve::ErrorKind::Forbidden => {
122 Self::newc(ErrorKind::AccessDenied, e.source())
123 }
124 hyper_static::serve::ErrorKind::BadRequest => {
125 Self::newc(ErrorKind::InvalidParameter, e.source())
126 }
127 }
128 }
129}