1use std::net::SocketAddr;
5use std::panic::AssertUnwindSafe;
6use std::sync::Arc;
7use std::task::{self, Poll};
8
9use futures_util::future::{BoxFuture, FutureExt};
10use hyper::service::Service;
11use hyper::{Body, Request, Response};
12
13use crate::handler::NewHandler;
14use crate::state::State;
15
16mod trap;
17
18pub use trap::call_handler;
19
20pub(crate) struct GothamService<T>
23where
24 T: NewHandler + 'static,
25{
26 handler: Arc<T>,
27}
28
29impl<T> GothamService<T>
30where
31 T: NewHandler + 'static,
32{
33 pub(crate) fn new(handler: T) -> GothamService<T> {
34 GothamService {
35 handler: Arc::new(handler),
36 }
37 }
38
39 pub(crate) fn connect(&self, client_addr: SocketAddr) -> ConnectedGothamService<T> {
40 ConnectedGothamService {
41 client_addr,
42 handler: self.handler.clone(),
43 }
44 }
45}
46
47pub(crate) struct ConnectedGothamService<T>
50where
51 T: NewHandler + 'static,
52{
53 handler: Arc<T>,
54 client_addr: SocketAddr,
55}
56
57impl<T> Service<Request<Body>> for ConnectedGothamService<T>
58where
59 T: NewHandler,
60{
61 type Response = Response<Body>;
62 type Error = anyhow::Error;
63 type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
64
65 fn poll_ready(
66 &mut self,
67 _cx: &mut task::Context<'_>,
68 ) -> Poll<std::result::Result<(), Self::Error>> {
69 Poll::Ready(Ok(()))
70 }
71
72 fn call<'a>(&'a mut self, req: Request<Body>) -> Self::Future {
73 let state = State::from_request(req, self.client_addr);
74 call_handler(self.handler.clone(), AssertUnwindSafe(state)).boxed()
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 use hyper::{Body, StatusCode};
83
84 use crate::helpers::http::response::create_empty_response;
85 use crate::router::builder::*;
86 use crate::state::State;
87
88 fn handler(state: State) -> (State, Response<Body>) {
89 let res = create_empty_response(&state, StatusCode::ACCEPTED);
90 (state, res)
91 }
92
93 #[test]
94 fn new_handler_closure() {
95 let service = GothamService::new(|| Ok(handler));
96
97 let req = Request::get("http://localhost/")
98 .body(Body::empty())
99 .unwrap();
100 let f = service
101 .connect("127.0.0.1:10000".parse().unwrap())
102 .call(req);
103 let response = futures_executor::block_on(f).unwrap();
104 assert_eq!(response.status(), StatusCode::ACCEPTED);
105 }
106
107 #[test]
108 fn router() {
109 let router = build_simple_router(|route| {
110 route.get("/").to(handler);
111 });
112
113 let service = GothamService::new(router);
114
115 let req = Request::get("http://localhost/")
116 .body(Body::empty())
117 .unwrap();
118 let f = service
119 .connect("127.0.0.1:10000".parse().unwrap())
120 .call(req);
121 let response = futures_executor::block_on(f).unwrap();
122 assert_eq!(response.status(), StatusCode::ACCEPTED);
123 }
124}