use super::HTTP_PORT;
use crate::{api::proxy_http_request, ctx::ClientContext};
use hyper::{
http::uri::PathAndQuery,
service::{make_service_fn, service_fn},
Body, Request, Response, Server, StatusCode,
};
use log::error;
use std::{
convert::Infallible,
io::ErrorKind,
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
sync::Arc,
};
pub async fn start_http_server(ctx: Arc<ClientContext>) -> std::io::Result<()> {
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, HTTP_PORT));
let make_svc = make_service_fn(move |_conn| {
let ctx = ctx.clone();
async move {
Ok::<_, Infallible>(service_fn(move |request| handle(request, ctx.clone())))
}
});
let server = Server::bind(&addr).serve(make_svc);
server
.await
.map_err(|err| std::io::Error::new(ErrorKind::Other, err))
}
async fn handle(
request: Request<Body>,
ctx: Arc<ClientContext>,
) -> Result<Response<Body>, Infallible> {
let path_and_query = request
.uri()
.path_and_query()
.map(PathAndQuery::as_str)
.unwrap_or_default();
let path_and_query = path_and_query.strip_prefix('/').unwrap_or(path_and_query);
let url = match ctx.base_url.join(path_and_query) {
Ok(value) => value,
Err(err) => {
error!("Failed to create HTTP proxy URL: {}", err);
let mut response = Response::default();
*response.status_mut() = StatusCode::SERVICE_UNAVAILABLE;
return Ok(response);
}
};
let response = match proxy_http_request(&ctx.http_client, url).await {
Ok(value) => value,
Err(err) => {
error!("Failed to proxy HTTP request: {}", err);
let mut response = Response::default();
*response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
return Ok(response);
}
};
Ok(response)
}