blob: 06ea0b55391c60f86aa4a1cd2df0ab6bc6e4420f [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::responder::Responder;
use anyhow::{anyhow, Error};
use async_trait::async_trait;
use fuchsia_async as fasync;
use futures::lock::Mutex;
use futures::TryStreamExt;
use hyper::service::{make_service_fn, service_fn};
use mockall::automock;
use std::convert::Infallible;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::Arc;
#[automock]
#[async_trait]
pub trait WebServer: Sync + Send {
async fn run(
&self,
port: u16,
responder1: Arc<futures::lock::Mutex<dyn Responder>>,
) -> Result<(), Error>;
}
pub struct WebServerImpl {}
#[async_trait]
impl WebServer for WebServerImpl {
/// Runs a Hyper webserver and passes requests to responder.handle().
async fn run(&self, port: u16, responder: Arc<Mutex<dyn Responder>>) -> Result<(), Error> {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), port);
let listener = fasync::net::TcpListener::bind(&addr)?;
let listener = listener
.accept_stream()
.map_ok(|(stream, _): (_, SocketAddr)| fuchsia_hyper::TcpStream { stream });
// Nested-cloning explanation at: https://www.fpcomplete.com/blog/captures-closures-async/
let make_svc = make_service_fn(move |_conn| {
let responder = responder.clone();
async move {
Ok::<_, Infallible>(service_fn(move |req| {
let responder = responder.clone();
async move {
let locked_responder = responder.lock().await;
(*locked_responder).handle(req)
}
}))
}
});
let server = hyper::Server::builder(hyper::server::accept::from_stream(listener))
.executor(fuchsia_hyper::Executor)
.serve(make_svc);
server.await.map_err(|e| anyhow!("Hyper Server Shutdown {:?}", e))
}
}