2023-01-19 17:18:41 +00:00
|
|
|
use crate::prelude::*;
|
|
|
|
|
2023-01-25 12:50:14 +00:00
|
|
|
use std::convert::Infallible;
|
2023-01-27 20:43:20 +00:00
|
|
|
use std::sync::Arc;
|
2023-01-25 12:50:14 +00:00
|
|
|
|
2023-01-27 20:43:20 +00:00
|
|
|
use http_body_util::{BodyExt, Full};
|
2023-01-19 17:18:41 +00:00
|
|
|
use hyper::server::conn::http1;
|
|
|
|
use hyper::{body::Bytes, service::service_fn, Request, Response};
|
2023-01-27 20:43:20 +00:00
|
|
|
use hyper::{Method, StatusCode};
|
2023-01-19 17:18:41 +00:00
|
|
|
|
2023-01-27 20:43:20 +00:00
|
|
|
use prometheus::{Encoder, IntGauge, Opts, Registry, TextEncoder};
|
|
|
|
use tokio::net::TcpListener;
|
2023-01-25 12:50:14 +00:00
|
|
|
use tokio::sync::oneshot::Sender;
|
|
|
|
use tokio::task::JoinHandle;
|
2023-01-19 17:18:41 +00:00
|
|
|
|
2023-01-25 12:50:14 +00:00
|
|
|
mod ws;
|
|
|
|
|
2023-01-26 21:11:28 +00:00
|
|
|
type BoxBody = http_body_util::combinators::BoxBody<Bytes, Infallible>;
|
|
|
|
|
|
|
|
async fn hello(
|
|
|
|
_: Request<hyper::body::Incoming>,
|
|
|
|
) -> std::result::Result<Response<Full<Bytes>>, Infallible> {
|
|
|
|
Ok(Response::new(Full::new(Bytes::from("Hello World!"))))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn not_found() -> std::result::Result<Response<Full<Bytes>>, Infallible> {
|
|
|
|
let mut response = Response::new(Full::new(Bytes::from("404")));
|
|
|
|
*response.status_mut() = StatusCode::NOT_FOUND;
|
|
|
|
Ok(response)
|
|
|
|
}
|
|
|
|
|
2023-01-27 20:43:20 +00:00
|
|
|
fn metrics(registry: Arc<Registry>) -> std::result::Result<Response<Full<Bytes>>, Infallible> {
|
|
|
|
let mf = registry.gather();
|
|
|
|
let mut buffer = vec![];
|
|
|
|
let encoder = TextEncoder::new();
|
|
|
|
encoder
|
|
|
|
.encode(&mf, &mut buffer)
|
|
|
|
.expect("write to vec cannot fail");
|
|
|
|
|
|
|
|
Ok(Response::new(Full::new(Bytes::from(buffer))))
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn route(
|
|
|
|
registry: Arc<Registry>,
|
|
|
|
request: Request<hyper::body::Incoming>,
|
|
|
|
) -> std::result::Result<Response<BoxBody>, Infallible> {
|
2023-01-26 21:11:28 +00:00
|
|
|
match (request.method(), request.uri().path()) {
|
|
|
|
(&Method::GET, "/hello") => Ok(hello(request).await?.map(BodyExt::boxed)),
|
|
|
|
(&Method::GET, "/socket") => Ok(ws::handle_request(request).await?.map(BodyExt::boxed)),
|
2023-01-27 20:43:20 +00:00
|
|
|
(&Method::GET, "/metrics") => Ok(metrics(registry)?.map(BodyExt::boxed)),
|
2023-01-26 21:11:28 +00:00
|
|
|
_ => Ok(not_found()?.map(BodyExt::boxed)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-19 17:18:41 +00:00
|
|
|
pub struct HttpServerActor {
|
|
|
|
terminator: Sender<()>,
|
|
|
|
fiber: JoinHandle<Result<()>>,
|
|
|
|
}
|
|
|
|
impl HttpServerActor {
|
2023-01-27 20:43:20 +00:00
|
|
|
pub async fn launch(listener: TcpListener, metrics: Arc<Registry>) -> Result<HttpServerActor> {
|
2023-01-19 17:18:41 +00:00
|
|
|
let (terminator, receiver) = tokio::sync::oneshot::channel::<()>();
|
2023-01-27 20:43:20 +00:00
|
|
|
let fiber = tokio::task::spawn(Self::main_loop(listener, receiver, metrics));
|
2023-01-19 17:18:41 +00:00
|
|
|
Ok(HttpServerActor { terminator, fiber })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn terminate(self) -> Result<()> {
|
|
|
|
match self.terminator.send(()) {
|
|
|
|
Ok(_) => {}
|
|
|
|
Err(_) => failure("wat")?,
|
|
|
|
}
|
|
|
|
self.fiber.await??;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-01-27 20:43:20 +00:00
|
|
|
async fn main_loop(
|
|
|
|
listener: TcpListener,
|
|
|
|
termination: impl Future,
|
|
|
|
registry: Arc<Registry>,
|
|
|
|
) -> Result<()> {
|
2023-01-19 17:18:41 +00:00
|
|
|
log::info!("Starting the http server");
|
|
|
|
pin!(termination);
|
2023-01-27 20:43:20 +00:00
|
|
|
let reqs = IntGauge::with_opts(Opts::new("sockets", "Number of open sockets"))?;
|
|
|
|
registry.register(Box::new(reqs.clone()))?;
|
2023-01-19 17:18:41 +00:00
|
|
|
|
|
|
|
loop {
|
|
|
|
select! {
|
|
|
|
_ = &mut termination => {
|
|
|
|
log::info!("Terminating the http server");
|
|
|
|
return Ok(())
|
|
|
|
},
|
|
|
|
result = listener.accept() => {
|
|
|
|
let (stream, _) = result?;
|
2023-01-27 20:43:20 +00:00
|
|
|
let c = registry.clone();
|
|
|
|
let reqs = reqs.clone();
|
2023-01-19 17:18:41 +00:00
|
|
|
tokio::task::spawn(async move {
|
2023-01-27 20:43:20 +00:00
|
|
|
reqs.inc();
|
|
|
|
let c = c.clone();
|
2023-01-19 17:18:41 +00:00
|
|
|
if let Err(err) = http1::Builder::new()
|
2023-01-27 20:43:20 +00:00
|
|
|
.serve_connection(stream, service_fn(move |r| route(c.clone(), r)))
|
2023-01-25 12:50:14 +00:00
|
|
|
.with_upgrades()
|
2023-01-19 17:18:41 +00:00
|
|
|
.await
|
|
|
|
{
|
|
|
|
tracing::error!("Error serving connection: {:?}", err);
|
|
|
|
}
|
2023-01-27 20:43:20 +00:00
|
|
|
reqs.dec();
|
2023-01-19 17:18:41 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|