use crate::LambdaRuntimeApiClient;
use hyper::{
body::{Body, Incoming},
server::conn::http1,
service::service_fn,
Request, Response,
};
use hyper_util::rt::TokioIo;
use std::{future::Future, net::SocketAddr};
use tokio::{net::TcpListener, sync::Mutex};
pub struct MockLambdaRuntimeApiServer(TcpListener);
impl MockLambdaRuntimeApiServer {
pub async fn bind(port: u16) -> Self {
let addr = SocketAddr::from(([127, 0, 0, 1], port));
Self(
TcpListener::bind(addr)
.await
.expect("Failed to bind for proxy server"),
)
}
pub async fn handle_next<ResBody, Fut>(&self, processor: impl Fn(Request<Incoming>) -> Fut)
where
ResBody: hyper::body::Body + 'static,
<ResBody as Body>::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
Fut: Future<Output = hyper::Result<Response<ResBody>>>,
{
let (stream, _) = self.0.accept().await.expect("Failed to accept connection");
let io = TokioIo::new(stream);
if let Err(err) = http1::Builder::new()
.serve_connection(io, service_fn(|req| async { processor(req).await }))
.await
{
println!("Error serving connection: {:?}", err);
}
}
pub async fn serve<ResBody, Fut>(&self, processor: impl Fn(Request<Incoming>) -> Fut)
where
Fut: Future<Output = hyper::Result<Response<ResBody>>>,
ResBody: hyper::body::Body + 'static,
<ResBody as Body>::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
{
loop {
self.handle_next(&processor).await
}
}
pub async fn passthrough(&self, client: LambdaRuntimeApiClient<Incoming>) {
let client = Mutex::new(client);
self
.serve(|req| async { client.lock().await.send_request(req).await })
.await
}
}