Skip to content

Commit

Permalink
Update tokio examples
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Yuan <[email protected]>
  • Loading branch information
juntao committed Jul 18, 2024
1 parent 794687c commit 0ea42d3
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 35 deletions.
2 changes: 1 addition & 1 deletion docs/develop/rust/_category_.json
Original file line number Diff line number Diff line change
Expand Up @@ -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."
}
}
8 changes: 7 additions & 1 deletion docs/develop/rust/database/my_sql_driver.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ The database connection is necessary for today's enterprise development. WasmEdg

<!-- prettier-ignore -->
:::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
Expand All @@ -26,6 +27,11 @@ RUSTFLAGS="--cfg wasmedge --cfg tokio_unstable" cargo build --target wasm32-wasi
wasmedge --env "DATABASE_URL=mysql://user:[email protected]:3306/mysql" target/wasm32-wasi/release/crud.wasm
```

<!-- prettier-ignore -->
:::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.

Expand Down
5 changes: 3 additions & 2 deletions docs/develop/rust/http_service/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ WasmEdge allows Rust developers to use APIs they are already familiar with to ac

<!-- prettier-ignore -->
:::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.
Expand Down Expand Up @@ -58,7 +59,7 @@ tokio = { version = "1", features = ["rt", "macros", "net", "time"] }

<!-- prettier-ignore -->
:::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.
Expand Down
81 changes: 53 additions & 28 deletions docs/develop/rust/http_service/server.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

<!-- prettier-ignore -->
:::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.
Expand All @@ -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()
}
}
```

Expand Down
12 changes: 9 additions & 3 deletions docs/develop/rust/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down

0 comments on commit 0ea42d3

Please sign in to comment.