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>, } impl HttpServerActor { pub async fn launch(listener: TcpListener) -> Result { 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, ) -> std::result::Result>, 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); } }); }, } } } }