pub(crate) async fn serve(
    config: &Config,
    api_root: api::RootNode,
    api_context: api::Context,
) -> Result<()> {
    let assets = Assets::init(config).await.context("failed to initialize assets")?;
    let ctx = Arc::new(Context::new(api_root, api_context, assets));

    // This sets up all the hyper server stuff. It's a bit of magic and touching
    // this code likely results in strange lifetime errors.
    //
    // In short: a hyper "service" is something that can handle requests. The
    // outer closure is called whenever hyper needs a new service instance (as
    // far as I understand it, it does that only for each worker thread, for
    // example). The inner closure is actually called each time a request is
    // received. Seems a bit more complicated than a single "handler" function,
    // but I'm sure hyper knows what they are doing.
    //
    // All our logic is encoded in the function `handle`. The only thing we are
    // doing here is to pass the context to that function, and clone its `Arc`
    // accordingly.
    //
    // We wrap the factory definition in a macro because we need two slightly
    // different factories. One for binding to a unix socket and one for
    // binding to a TCP socket. The code for defining the factory is exactly
    // the same, but due to type inference, it results in a different type. The
    // macro avoids code duplication.
    macro_rules! factory {
        () => {
            make_service_fn(move |_| {
                let ctx = Arc::clone(&ctx);
                async {
                    Ok::<_, Infallible>(service_fn(move |req| {
                        handle_internal_errors(handle(req, Arc::clone(&ctx)))
                    }))
                }
            })
        }
    }


    // Start the server with our service.
    if let Some(unix_socket) = &config.http.unix_socket {
        // Bind to Unix domain socket.
        if unix_socket.exists() {
            fs::remove_file(unix_socket)?;
        }
        let server = Server::bind_unix(&unix_socket)?.serve(factory!());
        info!("Listening on unix://{}", unix_socket.display());
        let permissions = fs::Permissions::from_mode(config.http.unix_socket_permissions);
        fs::set_permissions(unix_socket, permissions)?;
        server.await?;
    } else {
        // Bind to TCP socket.
        let addr = SocketAddr::new(config.http.address, config.http.port);
        let server = Server::bind(&addr).serve(factory!());
        info!("Listening on http://{}", server.local_addr());
        server.await?;
    }

    Ok(())
}
/// Starts the HTTP server. The future returned by this function must be awaited
/// to actually run it.
Starts the HTTP server. The future returned by this function must be awaited
to actually run it.
Starts the HTTP server . The future returned by this function must be awaited to actually run it .
pub(crate) async fn serve(
    config: &Config,
    api_root: api::RootNode,
    api_context: api::Context,
) -> Result<()> {
    let assets = Assets::init(config).await.context("failed to initialize assets")?;
    let ctx = Arc::new(Context::new(api_root, api_context, assets));
    // This sets up all the hyper server stuff. It's a bit of magic and touching
    // this code likely results in strange lifetime errors.
    //
    // In short: a hyper "service" is something that can handle requests. The
    // outer closure is called whenever hyper needs a new service instance (as
    // far as I understand it, it does that only for each worker thread, for
    // example). The inner closure is actually called each time a request is
    // received. Seems a bit more complicated than a single "handler" function,
    // but I'm sure hyper knows what they are doing.
    //
    // All our logic is encoded in the function `handle`. The only thing we are
    // doing here is to pass the context to that function, and clone its `Arc`
    // accordingly.
    //
    // We wrap the factory definition in a macro because we need two slightly
    // different factories. One for binding to a unix socket and one for
    // binding to a TCP socket. The code for defining the factory is exactly
    // the same, but due to type inference, it results in a different type. The
    // macro avoids code duplication.
    macro_rules! factory {
        () => {
            make_service_fn(move |_| {
                let ctx = Arc::clone(&ctx);
                async {
                    Ok::<_, Infallible>(service_fn(move |req| {
                        handle_internal_errors(handle(req, Arc::clone(&ctx)))
                    }))
                }
            })
        }
    }
    // Start the server with our service.
    if let Some(unix_socket) = &config.http.unix_socket {
        // Bind to Unix domain socket.
        if unix_socket.exists() {
            fs::remove_file(unix_socket)?;
        }
        let server = Server::bind_unix(&unix_socket)?.serve(factory!());
        info!("Listening on unix://{}", unix_socket.display());
        let permissions = fs::Permissions::from_mode(config.http.unix_socket_permissions);
        fs::set_permissions(unix_socket, permissions)?;
        server.await?;
    } else {
        // Bind to TCP socket.
        let addr = SocketAddr::new(config.http.address, config.http.port);
        let server = Server::bind(&addr).serve(factory!());
        info!("Listening on http://{}", server.local_addr());
        server.await?;
    }
    Ok(())
}
pub ( crate ) async fn serve ( config : & Config , api_root : api :: RootNode , api_context : api :: Context , ) -> Result < ( ) > { let assets = Assets :: init ( config ) . await . context ( " " ) ? ; let ctx = Arc :: new ( Context :: new ( api_root , api_context , assets ) ) ; // This sets up all the hyper server stuff. It's a bit of magic and touching // this code likely results in strange lifetime errors. // // In short: a hyper "service" is something that can handle requests. The // outer closure is called whenever hyper needs a new service instance (as // far as I understand it, it does that only for each worker thread, for // example). The inner closure is actually called each time a request is // received. Seems a bit more complicated than a single "handler" function, // but I'm sure hyper knows what they are doing. // // All our logic is encoded in the function `handle`. The only thing we are // doing here is to pass the context to that function, and clone its `Arc` // accordingly. // // We wrap the factory definition in a macro because we need two slightly // different factories. One for binding to a unix socket and one for // binding to a TCP socket. The code for defining the factory is exactly // the same, but due to type inference, it results in a different type. The // macro avoids code duplication. macro_rules! factory { ( ) => { make_service_fn ( move { let ctx Arc clone ( ctx ) async { Ok Infallible ( service_fn ( move req { handle_internal_errors ( handle ( req Arc clone ( ctx ) ) ) } ) ) } } ) } } // Start the server with our service. if let Some ( unix_socket ) = & config . http . unix_socket { // Bind to Unix domain socket. if unix_socket . exists ( ) { fs :: remove_file ( unix_socket ) ? ; } let server = Server :: bind_unix ( & unix_socket ) ? . serve ( factory ! ( ) ) ; info ! ( " " unix_socket display ( ) ) ; let permissions = fs :: Permissions :: from_mode ( config . http . unix_socket_permissions ) ; fs :: set_permissions ( unix_socket , permissions ) ? ; server . await ? ; } else { // Bind to TCP socket. let addr = SocketAddr :: new ( config . http . address , config . http . port ) ; let server = Server :: bind ( & addr ) . serve ( factory ! ( ) ) ; info ! ( " " server local_addr ( ) ) ; server . await ? ; } Ok ( ( ) ) }
Starts the HTTP server.
Starts the HTTP server .
config
&Config
api_root
api::RootNode
api_context
api::Context