From 0ea42d397fb5ec190fd604a3e13d1288325eac35 Mon Sep 17 00:00:00 2001 From: Michael Yuan Date: Tue, 16 Jul 2024 07:25:27 +0000 Subject: [PATCH] Update tokio examples Signed-off-by: Michael Yuan --- docs/develop/rust/_category_.json | 2 +- docs/develop/rust/database/my_sql_driver.md | 8 +- docs/develop/rust/http_service/client.md | 5 +- docs/develop/rust/http_service/server.md | 81 ++++++++++++++------- docs/develop/rust/setup.md | 12 ++- 5 files changed, 73 insertions(+), 35 deletions(-) diff --git a/docs/develop/rust/_category_.json b/docs/develop/rust/_category_.json index 5029aa84..54d18d9a 100644 --- a/docs/develop/rust/_category_.json +++ b/docs/develop/rust/_category_.json @@ -3,6 +3,6 @@ "position": 4, "link": { "type": "generated-index", - "description": "Rust is the first class citizen in WebAssembly ecosystem. In this chapter, we will learn how to create WASM apps in Rust." + "description": "Rust is well supported in the WebAssembly ecosystem. In this chapter, you will learn how to create Wasm apps in Rust." } } diff --git a/docs/develop/rust/database/my_sql_driver.md b/docs/develop/rust/database/my_sql_driver.md index 80033cff..79c18a54 100644 --- a/docs/develop/rust/database/my_sql_driver.md +++ b/docs/develop/rust/database/my_sql_driver.md @@ -8,7 +8,8 @@ The database connection is necessary for today's enterprise development. WasmEdg :::note -Before we start, ensure [you have Rust and WasmEdge installed](../setup.md). +Before we start, [you need to have Rust and WasmEdge installed](../setup.md). +Make sure that you read the [special notes on networking apps](../setup#special-notes) especially if you are compiling Rust programs on a Mac. ::: ## Run the example @@ -26,6 +27,11 @@ RUSTFLAGS="--cfg wasmedge --cfg tokio_unstable" cargo build --target wasm32-wasi wasmedge --env "DATABASE_URL=mysql://user:passwd@127.0.0.1:3306/mysql" target/wasm32-wasi/release/crud.wasm ``` + +:::note +Since we have TLS enabled by default in this example, you will need the [wasi-sdk version of clang](../setup#tls-on-macos) for compiling it on MacOS. +::: + To use TLS, you will need to turn on the `default-rustls` feature on the `mysql_async` crate in `Cargo.toml`. Then, run the application as follows. diff --git a/docs/develop/rust/http_service/client.md b/docs/develop/rust/http_service/client.md index 3c364c6c..c96bc306 100644 --- a/docs/develop/rust/http_service/client.md +++ b/docs/develop/rust/http_service/client.md @@ -8,7 +8,8 @@ WasmEdge allows Rust developers to use APIs they are already familiar with to ac :::note -Before we start, ensure [you have Rust and WasmEdge installed](../setup.md). +Before we start, [you need to have Rust and WasmEdge installed](../setup.md). +Make sure that you read the [special notes on networking apps](../setup#special-notes) especially if you are compiling Rust programs on a Mac. ::: We will discuss HTTP and HTTPS clients using popular Rust APIs. @@ -58,7 +59,7 @@ tokio = { version = "1", features = ["rt", "macros", "net", "time"] } :::note -The `Cargo.toml` here shows that TLS is enabled. If you need to compile it on the MacOS, you will need the [wasi-sdk version of clang](../setup#compile-rust-tls-on-macos). +The `Cargo.toml` here shows that TLS is enabled. If you need to compile it on the MacOS, you will need the [wasi-sdk version of clang](../setup#tls-on-macos). ::: The [example Rust code](https://github.com/WasmEdge/wasmedge_reqwest_demo/blob/main/src/http.rs) below shows an HTTP GET request. diff --git a/docs/develop/rust/http_service/server.md b/docs/develop/rust/http_service/server.md index c705ffe8..93947847 100644 --- a/docs/develop/rust/http_service/server.md +++ b/docs/develop/rust/http_service/server.md @@ -6,29 +6,33 @@ sidebar_position: 2 For WasmEdge to become a cloud-native runtime for microservices, it needs to support HTTP servers. By its very nature, the HTTP server is always asynchronous (non-blocking -- so that it can handle concurrent requests). This chapter will cover HTTP servers using popular Rust APIs. -- [The warp API](#the-warp-api) +- [The axum API](#the-warp-api) - [The hyper API](#the-hyper-api) :::note -Before we start, ensure [you have Rust and WasmEdge installed](../setup.md). +Before we start, [you need to have Rust and WasmEdge installed](../setup.md). +Make sure that you read the [special notes on networking apps](../setup#special-notes) especially if you are compiling Rust programs on a Mac. ::: -## The warp API +## The axum API -Use the warp API to create an asynchronous HTTP server. Build and run [the example](https://github.com/WasmEdge/wasmedge_hyper_demo/blob/main/server-warp/) in WasmEdge as follows. +The [axum](https://github.com/tokio-rs/axum) crate is the most popular HTTP server framework in the Rust Tokio ecosystem. +It is also the web framework for many popular services such as the [flows.network](https://flows.network) serverless platform for workflow functions. + +Use the axum API to create an asynchronous HTTP server. Build and run [the example](https://github.com/WasmEdge/wasmedge_hyper_demo/blob/main/server-axum/) in WasmEdge as follows. ```bash git clone https://github.com/WasmEdge/wasmedge_hyper_demo -cd wasmedge_hyper_demo/server-warp +cd wasmedge_hyper_demo/server-axum # Build the Rust code -cargo build --target wasm32-wasi --release +RUSTFLAGS="--cfg wasmedge --cfg tokio_unstable" cargo build --target wasm32-wasi --release # Use the AoT compiler for better performance -wasmedge compile target/wasm32-wasi/release/wasmedge_warp_server.wasm wasmedge_warp_server.wasm +wasmedge compile target/wasm32-wasi/release/wasmedge_axum_server.wasm wasmedge_axum_server.wasm # Run the example -wasmedge wasmedge_warp_server.wasm +wasmedge wasmedge_axum_server.wasm ``` Then from another terminal, you can request the server. The HTTP server echoes the request data and sends back the response. @@ -38,34 +42,55 @@ $ curl http://localhost:8080/echo -X POST -d "WasmEdge" WasmEdge ``` -In your Rust application, import the WasmEdge-adapted `warp_wasi` crate, which uses a special version of single-threaded Tokio adapted for WebAssembly. Just add the following lines to your `Cargo.toml`. +In your Rust application, you will apply a few patches developed by the WasmEdge community to replace +POSIX sockets with WasmEdge sockets in standard libraries. With those patches, you can then +use the official `tokio` and `axum` crates. + +``` +[patch.crates-io] +tokio = { git = "https://github.com/second-state/wasi_tokio.git", branch = "v1.36.x" } +socket2 = { git = "https://github.com/second-state/socket2.git", branch = "v0.5.x" } +hyper = { git = "https://github.com/second-state/wasi_hyper.git", branch = "v0.14.x" } -```toml [dependencies] -tokio_wasi = { version = "1", features = ["rt", "macros", "net", "time", "io-util"]} -warp_wasi = "0.3" +axum = "0.6" +bytes = "1" +futures-util = "0.3.30" +tokio = { version = "1", features = ["rt", "macros", "net", "time", "io-util"]} ``` -The [Rust example code](https://github.com/WasmEdge/wasmedge_hyper_demo/blob/main/server-warp/src/main.rs) below shows an HTTP server that echoes back any incoming request. +The [Rust example code](https://github.com/WasmEdge/wasmedge_hyper_demo/blob/main/server-axum/src/main.rs) below shows an HTTP server that responds to incoming requests for the `/` and `/echo` URL endpoints. ```rust #[tokio::main(flavor = "current_thread")] async fn main() { - // GET / - let help = warp::get() - .and(warp::path::end()) - .map(|| "Try POSTing data to /echo such as: `curl localhost:8080/echo -XPOST -d 'hello world'`\n"); - - // POST /echo - let echo = warp::post() - .and(warp::path("echo")) - .and(warp::body::bytes()) - .map(|body_bytes: bytes::Bytes| { - format!("{}\n", std::str::from_utf8(body_bytes.as_ref()).unwrap()) - }); - - let routes = help.or(echo); - warp::serve(routes).run(([0, 0, 0, 0], 8080)).await + // build our application with a route + let app = Router::new() + .route("/", get(help)) + .route("/echo", post(echo)); + + // run it + let addr = "0.0.0.0:8080"; + let tcp_listener = TcpListener::bind(addr).await.unwrap(); + println!("listening on {}", addr); + axum::Server::from_tcp(tcp_listener.into_std().unwrap()) + .unwrap() + .serve(app.into_make_service()) + .await + .unwrap(); +} +``` + +The `echo()` function is called when a `POST` request is received at `/echo`. The function receives and processes +the request body and returns bytes that are sent back as the response message. + +```rust +async fn echo(mut stream: BodyStream) -> Bytes { + if let Some(Ok(s)) = stream.next().await { + s + } else { + Bytes::new() + } } ``` diff --git a/docs/develop/rust/setup.md b/docs/develop/rust/setup.md index 84e5b416..2047432c 100644 --- a/docs/develop/rust/setup.md +++ b/docs/develop/rust/setup.md @@ -32,9 +32,9 @@ To build a WASM file running in server-side WebAssembly like WasmEdge, we need t rustup target add wasm32-wasi ``` -## Special notes +## Special notes for networking apps -### Async networking with tokio +### Tokio support WasmEdge supports async networking APIs provided by [Tokio](https://tokio.rs/) and related crates. If you have tokio in your `Cargo.toml`, you need to add a few config flags to help the Rust compiler choose the correct feature branches in the library source code. Here is an example of `cargo build` command for @@ -52,7 +52,13 @@ target = "wasm32-wasi" rustflags = ["--cfg", "wasmedge", "--cfg", "tokio_unstable"] ``` -### Compile Rust TLS on MacOS +Once you have these lines in `.cargo/config.toml`, you can simply use the regular `cargo` command. + +``` +cargo build --target wasm32-wasi --release +``` + +### TLS on MacOS The standard `cargo` toolchain can support the [Rust TLS](https://github.com/rustls/rustls) library on Linux. However, on MacOS, you need a special version of the Clang tool, released from the official [wasi-sdk](https://github.com/WebAssembly/wasi-sdk), in order to support TLS libraries.