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/*!
13# Trillium server adapter for aws lambda
14
15```rust,no_run
16trillium_aws_lambda::run(|conn: trillium::Conn| async move {
17    conn.ok("hello lambda")
18});
19```
20*/
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, 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>);
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(request, context, Arc::clone(&self.0)))
47    }
48}
49
50async fn run_handler(conn: HttpConn<Synthetic>, handler: Arc<impl Handler>) -> Conn {
51    let conn = handler.run(conn.into()).await;
52    handler.before_send(conn).await
53}
54
55async fn handler_fn(
56    request: LambdaRequest,
57    context: Context,
58    handler: Arc<impl Handler>,
59) -> std::io::Result<LambdaResponse> {
60    match request {
61        LambdaRequest::Alb(request) => {
62            let mut conn = request.into_conn().await;
63            conn.state_mut().insert(LambdaContext::new(context));
64            let conn = run_handler(conn, handler).await;
65            Ok(LambdaResponse::Alb(AlbResponse::from_conn(conn).await))
66        }
67
68        LambdaRequest::AlbMultiHeaders(request) => {
69            let mut conn = request.into_conn().await;
70            conn.state_mut().insert(LambdaContext::new(context));
71            let conn = run_handler(conn, handler).await;
72            Ok(LambdaResponse::AlbMultiHeaders(
73                AlbMultiHeadersResponse::from_conn(conn).await,
74            ))
75        }
76    }
77}
78/**
79# Runs a trillium handler on an already-running tokio runtime
80
81This function will poll pending until the server shuts down.
82*/
83pub async fn run_async(mut handler: impl Handler) {
84    let mut info = "aws lambda".into();
85    handler.init(&mut info).await;
86    lamedh_runtime::run(HandlerWrapper(Arc::new(handler)))
87        .await
88        .unwrap()
89}
90
91/**
92# Runs a trillium handler in a sync context
93
94This function creates a new tokio runtime and executes the handler on
95it for aws lambda.
96
97This function will block the current thread until the server shuts
98down
99*/
100
101pub fn run(handler: impl Handler) {
102    runtime::Builder::new_current_thread()
103        .enable_all()
104        .build()
105        .unwrap()
106        .block_on(run_async(handler));
107}