Skip to main content

trillium_aws_lambda/
lib.rs

1#![forbid(unsafe_code)]
2#![deny(
3    clippy::dbg_macro,
4    missing_copy_implementations,
5    rustdoc::missing_crate_level_docs,
6    missing_debug_implementations,
7    missing_docs,
8    nonstandard_style,
9    unused_qualifications
10)]
11
12//! # Trillium server adapter for aws lambda
13//!
14//! ```rust,no_run
15//! trillium_aws_lambda::run(|conn: trillium::Conn| async move { conn.ok("hello lambda") });
16//! ```
17
18#[cfg(test)]
19#[doc = include_str!("../README.md")]
20mod readme {}
21
22use lamedh_runtime::{Context, Handler as AwsHandler};
23use std::{future::Future, pin::Pin, sync::Arc};
24use tokio::runtime;
25use trillium::{Conn, Handler};
26use trillium_http::{Conn as HttpConn, ServerConfig, Synthetic};
27
28mod context;
29pub use context::LambdaConnExt;
30use context::LambdaContext;
31
32mod request;
33use request::LambdaRequest;
34
35mod response;
36use response::{AlbMultiHeadersResponse, AlbResponse, LambdaResponse};
37
38#[derive(Debug)]
39struct HandlerWrapper<H>(Arc<H>, Arc<ServerConfig>);
40
41impl<H: Handler> AwsHandler<LambdaRequest, LambdaResponse> for HandlerWrapper<H> {
42    type Error = std::io::Error;
43    type Fut = Pin<Box<dyn Future<Output = Result<LambdaResponse, Self::Error>> + Send + 'static>>;
44
45    fn call(&mut self, request: LambdaRequest, context: Context) -> Self::Fut {
46        Box::pin(handler_fn(
47            request,
48            context,
49            Arc::clone(&self.0),
50            Arc::clone(&self.1),
51        ))
52    }
53}
54
55async fn run_handler(conn: HttpConn<Synthetic>, handler: Arc<impl Handler>) -> Conn {
56    let conn = handler.run(conn.into()).await;
57    handler.before_send(conn).await
58}
59
60async fn handler_fn(
61    request: LambdaRequest,
62    context: Context,
63    handler: Arc<impl Handler>,
64    server_config: Arc<ServerConfig>,
65) -> std::io::Result<LambdaResponse> {
66    match request {
67        LambdaRequest::Alb(request) => {
68            let mut conn = request.into_conn().await.with_server_config(server_config);
69            conn.state_mut().insert(LambdaContext::new(context));
70            let conn = run_handler(conn, handler).await;
71            Ok(LambdaResponse::Alb(AlbResponse::from_conn(conn).await))
72        }
73
74        LambdaRequest::AlbMultiHeaders(request) => {
75            let mut conn = request.into_conn().await.with_server_config(server_config);
76            conn.state_mut().insert(LambdaContext::new(context));
77            let conn = run_handler(conn, handler).await;
78            Ok(LambdaResponse::AlbMultiHeaders(
79                AlbMultiHeadersResponse::from_conn(conn).await,
80            ))
81        }
82    }
83}
84/// # Runs a trillium handler on an already-running tokio runtime
85///
86/// This function will poll pending until the server shuts down.
87pub async fn run_async(mut handler: impl Handler) {
88    let mut info = ServerConfig::default().into();
89    handler.init(&mut info).await;
90    lamedh_runtime::run(HandlerWrapper(Arc::new(handler), Arc::new(info.into())))
91        .await
92        .unwrap()
93}
94
95/// # Runs a trillium handler in a sync context
96///
97/// This function creates a new tokio runtime and executes the handler on
98/// it for aws lambda.
99///
100/// This function will block the current thread until the server shuts
101/// down
102pub fn run(handler: impl Handler) {
103    runtime::Builder::new_current_thread()
104        .enable_all()
105        .build()
106        .unwrap()
107        .block_on(run_async(handler));
108}