prosa_hyper/server/
adaptor.rs1use std::convert::Infallible;
3
4use bytes::Bytes;
5use http::response;
6use http_body_util::{Empty, Full, combinators::BoxBody};
7use hyper::{Request, Response, StatusCode};
8use prosa::core::{adaptor::Adaptor, error::ProcError, msg::ErrorMsg, proc::ProcBusParam as _};
9
10use crate::{HttpError, HyperResp, PRODUCT_VERSION_HEADER};
11
12use super::proc::HyperServerProc;
13
14#[cfg_attr(doc, aquamarine::aquamarine)]
15pub trait HyperServerAdaptor<M>
26where
27 M: 'static
28 + std::marker::Send
29 + std::marker::Sync
30 + std::marker::Sized
31 + std::clone::Clone
32 + std::fmt::Debug
33 + prosa::core::msg::Tvf
34 + std::default::Default,
35{
36 fn new(proc: &HyperServerProc<M>) -> Result<Self, Box<dyn ProcError + Send + Sync>>
38 where
39 Self: Sized;
40
41 fn response_builder<T>(&self, status_code: T) -> response::Builder
44 where
45 T: TryInto<StatusCode>,
46 <T as TryInto<StatusCode>>::Error: Into<http::Error>,
47 {
48 Response::builder()
49 .status(status_code)
50 .header(hyper::header::SERVER, PRODUCT_VERSION_HEADER)
51 }
52
53 fn process_http_request(
55 &self,
56 req: Request<hyper::body::Incoming>,
57 ) -> impl std::future::Future<Output = HyperResp<Self, M>> + Send
58 where
59 Self: Sized + Send + Sync + 'static,
60 M: 'static
61 + Send
62 + Sync
63 + Sized
64 + Clone
65 + std::fmt::Debug
66 + prosa::core::msg::Tvf
67 + Default;
68}
69
70pub fn default_srv_error_response<M, F>(
80 err: &ErrorMsg<M>,
81 response_builder: F,
82) -> Result<Response<BoxBody<Bytes, Infallible>>, HttpError>
83where
84 M: 'static
85 + std::marker::Send
86 + std::marker::Sync
87 + std::marker::Sized
88 + std::clone::Clone
89 + std::fmt::Debug
90 + prosa::core::msg::Tvf
91 + std::default::Default,
92 F: Fn(StatusCode) -> response::Builder,
93{
94 match err.get_err() {
95 prosa::core::service::ServiceError::NoError(_) => response_builder(StatusCode::ACCEPTED)
96 .body(BoxBody::new(Empty::<Bytes>::new()))
97 .map_err(|e| e.into()),
98 prosa::core::service::ServiceError::UnableToReachService(_) => {
99 response_builder(StatusCode::SERVICE_UNAVAILABLE)
100 .body(BoxBody::new(Full::new(Bytes::from("Can't reach service"))))
101 .map_err(|e| e.into())
102 }
103 prosa::core::service::ServiceError::Timeout(_, _) => {
104 response_builder(StatusCode::GATEWAY_TIMEOUT)
105 .body(BoxBody::new(Empty::<Bytes>::new()))
106 .map_err(|e| e.into())
107 }
108 prosa::core::service::ServiceError::ProtocolError(_) => {
109 response_builder(StatusCode::BAD_GATEWAY)
110 .body(BoxBody::new(Empty::<Bytes>::new()))
111 .map_err(|e| e.into())
112 }
113 }
114}
115
116#[derive(Debug, Adaptor, Clone)]
118pub struct HelloHyperServerAdaptor {
119 hello_msg: String,
120}
121
122impl<M> HyperServerAdaptor<M> for HelloHyperServerAdaptor
123where
124 M: 'static
125 + std::marker::Send
126 + std::marker::Sync
127 + std::marker::Sized
128 + std::clone::Clone
129 + std::fmt::Debug
130 + prosa::core::msg::Tvf
131 + std::default::Default,
132{
133 fn new(proc: &HyperServerProc<M>) -> Result<Self, Box<dyn ProcError + Send + Sync>> {
134 Ok(HelloHyperServerAdaptor {
135 hello_msg: format!("Hello from {}", proc.name()),
136 })
137 }
138
139 async fn process_http_request(
140 &self,
141 _req: Request<hyper::body::Incoming>,
142 ) -> HyperResp<Self, M> {
143 Response::builder()
144 .status(200)
145 .header("Server", PRODUCT_VERSION_HEADER)
146 .body(BoxBody::new(Full::new(Bytes::from(self.hello_msg.clone()))))
147 .into()
148 }
149}