use crate::SalvoRoute;
use alux_http::{HttpServerAlg, HttpServerSetup};
use core::time::Duration;
use salvo::conn::tcp::TcpAcceptor;
use salvo::server::ServerHandle;
use tokio::net::TcpListener;
use tokio::task::JoinHandle;
type SalvoServerError = Box<dyn std::error::Error + Send + Sync>;
const DRAIN: Duration = Duration::from_secs(5);
#[derive(Debug, Default)]
pub struct SalvoServer;
pub struct SalvoOpen {
handle: ServerHandle,
task: JoinHandle<Result<(), SalvoServerError>>,
}
impl Drop for SalvoOpen {
fn drop(&mut self) {
self.handle.stop_graceful(DRAIN);
self.task.abort();
}
}
impl HttpServerAlg for SalvoServer {
type Program = SalvoRoute;
type Open = SalvoOpen;
type Error = SalvoServerError;
async fn open(&mut self, setup: HttpServerSetup<Self::Program>) -> Result<Self::Open, Self::Error> {
let (bind, route) = setup.into_parts();
let acceptor = TcpAcceptor::try_from(TcpListener::bind(bind.address()).await?)?;
let server = salvo::Server::new(acceptor);
let handle = server.handle();
let task = tokio::task::spawn_local(async move {
server.serve(route.into_salvo()).await;
Ok(())
});
Ok(SalvoOpen { handle, task })
}
async fn close(&mut self, open: &mut Self::Open) -> Result<(), Self::Error> {
open.handle.stop_graceful(DRAIN);
if !open.task.is_finished() {
let _ = (&mut open.task).await;
}
Ok(())
}
async fn end(&mut self, open: &mut Self::Open) -> Result<(), Self::Error> {
self.close(open).await
}
}