sammhicks / picoserve

An async no_std HTTP server suitable for bare-metal environments, heavily inspired by axum
MIT License
177 stars 20 forks source link

picoserve

An async no_std HTTP server suitable for bare-metal environments, heavily inspired by axum. It was designed with embassy on the Raspberry Pi Pico W in mind, but should work with other embedded runtimes and hardware.

Features:

Shortcomings:

Usage examples

tokio (for testing purposes)

use std::time::Duration;

use picoserve::routing::get;

#[tokio::main(flavor = "current_thread")]
async fn main() -> anyhow::Result<()> {
    let port = 8000;

    let app =
        std::rc::Rc::new(picoserve::Router::new().route("/", get(|| async { "Hello World" })));

    let config = picoserve::Config::new(picoserve::Timeouts {
        start_read_request: Some(Duration::from_secs(5)),
        read_request: Some(Duration::from_secs(1)),
        write: Some(Duration::from_secs(1)),
    })
    .keep_connection_alive();

    let socket = tokio::net::TcpListener::bind((std::net::Ipv4Addr::LOCALHOST, 8000)).await?;

    println!("http://localhost:{port}/");

    tokio::task::LocalSet::new()
        .run_until(async {
            loop {
                let (stream, remote_address) = socket.accept().await?;

                println!("Connection from {remote_address}");

                let app = app.clone();
                let config = config.clone();

                tokio::task::spawn_local(async move {
                    match picoserve::serve(&app, &config, &mut [0; 2048], stream).await {
                        Ok(handled_requests_count) => {
                            println!(
                                "{handled_requests_count} requests handled from {remote_address}"
                            )
                        }
                        Err(err) => println!("{err:?}"),
                    }
                });
            }
        })
        .await
}