titan_lambda/
lambda_handler_service.rs

1use std::{
2  future::Future,
3  marker::PhantomData,
4  pin::Pin,
5  task::{Context, Poll},
6};
7
8use futures_util::FutureExt as _;
9use lambda_http::lambda_runtime::Diagnostic;
10use titan_core::{FromRequest, Handler, Respondable, Service};
11
12use lambda_http::{Body as LambdaBody, Request as LambdaRequest};
13use titan_http::{Request, Response};
14
15pub struct LambdaHandlerService<H, Args> {
16  f: H,
17  _args: PhantomData<Args>,
18}
19
20impl<F, Args> LambdaHandlerService<F, Args>
21where
22  F: Handler<Args>,
23  F::Output: Respondable,
24  F::Future: Send + 'static,
25{
26  pub(crate) fn new(f: F) -> Self {
27    Self { f, _args: PhantomData }
28  }
29
30  pub async fn run(self) -> Result<(), lambda_http::Error>
31  where
32    Args: FromRequest,
33    F::Output: Respondable,
34    F::Future: Send,
35  {
36    lambda_http::run(self).await
37  }
38}
39
40#[derive(Debug)]
41pub struct LambdaError;
42
43impl From<LambdaError> for Diagnostic {
44  fn from(_: LambdaError) -> Diagnostic {
45    Diagnostic {
46      error_type: "strange".into(),
47      error_message: "this shouldn't happen".into(),
48    }
49  }
50}
51
52impl<H, Args> Service<LambdaRequest> for LambdaHandlerService<H, Args>
53where
54  Args: FromRequest,
55  H: Handler<Args>,
56  H::Future: Future<Output = H::Output> + Send + 'static,
57  H::Output: Respondable,
58{
59  type Response = Response<lambda_http::Body>;
60  type Error = LambdaError;
61
62  type Future =
63    Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
64
65  fn poll_ready(
66    &mut self,
67    _: &mut Context<'_>,
68  ) -> Poll<Result<(), Self::Error>> {
69    Poll::Ready(Ok(()))
70  }
71
72  fn call(&mut self, req: LambdaRequest) -> Self::Future {
73    let (parts, body) = req.into_parts();
74
75    let body = match body {
76      LambdaBody::Text(text) => text.as_bytes().to_vec(),
77      LambdaBody::Empty => Vec::default(),
78      LambdaBody::Binary(bin) => bin,
79    }
80    .into_boxed_slice();
81
82    let req = Request::from_parts(parts, body);
83
84    let args = match Args::from_request(req) {
85      Ok(value) => value,
86      Err(_) => return Box::pin(async move { Err(LambdaError) }),
87    };
88    let fut = self.f.call(args).map(|x| {
89      let body = x.respond();
90
91      let (parts, body) = body.into_parts();
92      let new_body = match body {
93        titan_http::body::Body::Full(full) => {
94          lambda_http::Body::Binary(full.to_vec())
95        }
96        titan_http::body::Body::Stream(_) => panic!("bnono"),
97      };
98      let res = titan_http::Response::from_parts(parts, new_body);
99      Ok(res)
100    });
101    Box::pin(fut)
102  }
103}