Skip to main content

threadloom_server/
lib.rs

1#[cfg(feature = "lambda")]
2pub use lambda_http;
3#[cfg(feature = "lambda")]
4pub use tokio;
5
6pub use http;
7use http::{Request, Response};
8use std::sync::Arc;
9use std::future::Future;
10use std::pin::Pin;
11
12pub type Bytes = Vec<u8>;
13pub type PortableRequest = Request<Bytes>;
14pub type PortableResponse = Response<Bytes>;
15
16pub trait Handler: Send + Sync + 'static {
17    fn handle(&self, req: PortableRequest) -> Pin<Box<dyn Future<Output = PortableResponse> + Send + '_>>;
18}
19
20pub struct Server {
21    pub routes: Vec<(String, Arc<dyn Handler>)>,
22}
23
24impl Default for Server {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29
30impl Server {
31    pub fn new() -> Self {
32        Self { routes: Vec::new() }
33    }
34
35    pub fn route<H: Handler>(&mut self, path: &str, handler: H) {
36        self.routes.push((path.to_string(), Arc::new(handler)));
37    }
38}
39
40#[cfg(feature = "actix")]
41pub mod actix_adapter {
42    use super::{Handler, Server};
43    use actix_web::{web, HttpRequest, HttpResponse};
44    use std::sync::Arc;
45
46
47    async fn actix_handler_wrapper(
48        req: HttpRequest,
49        body: web::Bytes,
50        handler: web::Data<Arc<dyn Handler>>,
51    ) -> HttpResponse {
52        let method = http::Method::try_from(req.method().as_str()).unwrap();
53        
54        let mut builder = http::Request::builder()
55            .method(method)
56            .uri(req.uri().to_string());
57
58        for (k, v) in req.headers() {
59            builder = builder.header(k.as_str(), v.as_bytes());
60        }
61
62        let portable_req = builder.body(body.to_vec()).unwrap();
63        let portable_res = handler.handle(portable_req).await;
64
65        let mut res_builder = HttpResponse::build(
66            actix_web::http::StatusCode::from_u16(portable_res.status().as_u16()).unwrap(),
67        );
68
69        for (k, v) in portable_res.headers() {
70            res_builder.append_header((k.as_str(), v.as_bytes()));
71        }
72
73        res_builder.body(portable_res.into_body())
74    }
75
76    pub fn configure(server: &Server, cfg: &mut actix_web::web::ServiceConfig) {
77        for (path, handler) in &server.routes {
78            let handler_data = web::Data::new(Arc::clone(handler));
79            cfg.service(
80                web::resource(path)
81                    .app_data(handler_data.clone())
82                    .route(web::post().to(actix_handler_wrapper))
83            );
84        }
85    }
86}
87
88#[cfg(feature = "lambda")]
89pub mod lambda_adapter {
90    use super::Server;
91    use lambda_http::{service_fn, Body, Error, Request, Response};
92    use std::sync::Arc;
93
94    pub async fn run(server: Server) -> Result<(), Error> {
95        let server = Arc::new(server);
96        let handler = service_fn(move |req: Request| {
97            let server_clone = Arc::clone(&server);
98            async move {
99                let path = req.uri().path().to_string();
100                let mut found_handler = None;
101                for (route_path, handler) in &server_clone.routes {
102                    if route_path == &path {
103                        found_handler = Some(Arc::clone(handler));
104                        break;
105                    }
106                }
107
108                if let Some(h) = found_handler {
109                    let (parts, body) = req.into_parts();
110                    let bytes = match body {
111                        Body::Text(t) => t.into_bytes(),
112                        Body::Binary(b) => b,
113                        Body::Empty => vec![],
114                    };
115                    let portable_req = http::Request::from_parts(parts, bytes);
116                    let res = h.handle(portable_req).await;
117                    let (parts, res_bytes) = res.into_parts();
118                    Ok::<Response<Body>, Error>(Response::from_parts(
119                        parts,
120                        Body::Binary(res_bytes),
121                    ))
122                } else {
123                    Ok(Response::builder().status(404).body(Body::Empty).unwrap())
124                }
125            }
126        });
127        lambda_http::run(handler).await
128    }
129}
130
131#[cfg(not(feature = "lambda"))]
132pub mod lambda_http {
133    #[derive(Debug)]
134    pub struct Error;
135}
136
137#[cfg(not(feature = "lambda"))]
138pub mod tokio {
139    pub mod runtime {
140        pub struct Builder;
141        impl Builder {
142            pub fn new_current_thread() -> Self { Self }
143            pub fn enable_all(&mut self) -> &mut Self { self }
144            pub fn build(&mut self) -> Result<Runtime, ()> { Ok(Runtime) }
145        }
146        pub struct Runtime;
147        impl Runtime {
148            pub fn block_on<F>(&self, _f: F) -> Result<(), crate::lambda_http::Error> { Ok(()) }
149        }
150    }
151}
152
153#[cfg(not(feature = "lambda"))]
154pub mod lambda_adapter {
155    use super::Server;
156    pub async fn run(_server: Server) -> Result<(), crate::lambda_http::Error> {
157        Ok(())
158    }
159}