titan_lambda/
lambda_handler_service.rs1use 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}