lavina/src/http.rs

63 lines
2.0 KiB
Rust

use crate::prelude::*;
use http_body_util::Full;
use hyper::server::conn::http1;
use hyper::{body::Bytes, service::service_fn, Request, Response};
use std::convert::Infallible;
use tokio::sync::oneshot::{Receiver, Sender};
use tokio::task::JoinHandle;
use tokio::net::TcpListener;
pub struct HttpServerActor {
terminator: Sender<()>,
fiber: JoinHandle<Result<()>>,
}
impl HttpServerActor {
pub async fn launch(listener: TcpListener) -> Result<HttpServerActor> {
let (terminator, receiver) = tokio::sync::oneshot::channel::<()>();
let fiber = tokio::task::spawn(Self::main_loop(listener, receiver));
Ok(HttpServerActor { terminator, fiber })
}
pub async fn terminate(self) -> Result<()> {
match self.terminator.send(()) {
Ok(_) => {}
Err(_) => failure("wat")?,
}
self.fiber.await??;
Ok(())
}
async fn hello(
_: Request<hyper::body::Incoming>,
) -> std::result::Result<Response<Full<Bytes>>, Infallible> {
Ok(Response::new(Full::new(Bytes::from("Hello World!"))))
}
async fn main_loop(listener: TcpListener, termination: impl Future) -> Result<()> {
log::info!("Starting the http server");
pin!(termination);
loop {
select! {
_ = &mut termination => {
log::info!("Terminating the http server");
return Ok(())
},
result = listener.accept() => {
let (stream, _) = result?;
tokio::task::spawn(async move {
if let Err(err) = http1::Builder::new()
.serve_connection(stream, service_fn(HttpServerActor::hello))
.await
{
tracing::error!("Error serving connection: {:?}", err);
}
});
},
}
}
}
}