1use crate::config;
2use bytes::Bytes;
3use http::{Request, Response, StatusCode};
4use http_body_util::{combinators::BoxBody, BodyExt, Empty};
5use hyper::{body::Incoming, service::service_fn};
6use hyper_util::{
7 rt::{TokioExecutor, TokioIo},
8 server::conn::auto::Builder,
9};
10use std::{convert::Infallible, net::SocketAddr};
11use tokio::net::TcpListener;
12use tracing::{debug, error, info};
13
14pub async fn start() -> anyhow::Result<()> {
15 match &config::get().monitor {
16 Some(cfg) => {
17 info!(address = cfg.address, "Starting monitor");
18 let addr: SocketAddr = cfg.address.parse()?;
19 let listener = TcpListener::bind(addr)
20 .await
21 .expect("Should bind to socket addr");
22
23 loop {
24 let (stream, addr) = match listener.accept().await {
25 Ok(a) => a,
26 Err(err) => {
27 error!(?err, "Failed to accepts connection");
28 continue;
29 }
30 };
31
32 if let Err(err) = Builder::new(TokioExecutor::new())
33 .serve_connection(TokioIo::new(stream), service_fn(handle_request))
34 .await
35 {
36 error!(?err, ?addr, "Failed to serve connections");
37 }
38 }
39 }
40 None => Ok(()),
41 }
42}
43
44async fn handle_request(
45 req: Request<Incoming>,
46) -> Result<Response<BoxBody<Bytes, Infallible>>, Infallible> {
47 match req.uri().path() {
48 "/healthz" => {
49 let res = Response::builder()
50 .status(StatusCode::NO_CONTENT)
51 .body(
52 Empty::<Bytes>::new()
53 .map_err(|never| match never {})
54 .boxed(),
55 )
56 .expect("Should build body");
57 debug!("monitor responded ok");
58 Ok(res)
59 }
60 _ => {
61 let res = Response::builder()
62 .status(StatusCode::NOT_FOUND)
63 .body(
64 Empty::<Bytes>::new()
65 .map_err(|never| match never {})
66 .boxed(),
67 )
68 .expect("Should build body");
69 debug!("monitor responded not found");
70 Ok(res)
71 }
72 }
73}