Skip to content

Commit

Permalink
[Docs] Update the Rust dev API part of the book (WasmEdge#1065)
Browse files Browse the repository at this point in the history
* Update rust.md

Signed-off-by: Michael Yuan <[email protected]>

* Update SUMMARY.md

Signed-off-by: Michael Yuan <[email protected]>

* Update bindgen.md

Signed-off-by: Michael Yuan <[email protected]>

* Update SUMMARY.md

Signed-off-by: Michael Yuan <[email protected]>

* Update networking.md

Signed-off-by: Michael Yuan <[email protected]>

* Update networking.md

Signed-off-by: Michael Yuan <[email protected]>

* Update rust.md

Signed-off-by: Michael Yuan <[email protected]>

* Update networking.md

Signed-off-by: Michael Yuan <[email protected]>

* Create networking-nonblocking.md

Signed-off-by: Michael Yuan <[email protected]>

* Update networking.md

Signed-off-by: Michael Yuan <[email protected]>

* Update rust.md

Signed-off-by: Michael Yuan <[email protected]>

* Update SUMMARY.md

Signed-off-by: Michael Yuan <[email protected]>

* Update networking.md

Signed-off-by: Michael Yuan <[email protected]>

Co-authored-by: hydai <[email protected]>
  • Loading branch information
juntao and hydai authored Feb 21, 2022
1 parent ee87448 commit 4e2fb5d
Show file tree
Hide file tree
Showing 6 changed files with 345 additions and 116 deletions.
45 changes: 23 additions & 22 deletions docs/book/en/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,29 @@
- [FAQ](intro/faq.md)

- [Develop a WasmEdge app](dev.md)
- [Rust](dev/rust.md)
- [Access OS services](dev/rust/wasi.md)
- [Tensorflow](dev/rust/tensorflow.md)
- [Networking sockets](dev/rust/networking.md)
- [Command interface](dev/rust/command.md)
- [rustwasmc](dev/rust/bindgen.md)
- [JavaScript](dev/js.md)
- [Getting started](dev/js/quickstart.md)
- [Networking sockets](dev/js/networking.md)
- [Fetch](dev/js/fetch.md)
- [Tensorflow](dev/js/tensorflow.md)
- [React SSR](dev/js/ssr.md)
- [ES6 module](dev/js/es6.md)
- [NodeJS &amp; NPM module](dev/js/npm.md)
- [Use Rust to implement JS API](dev/js/rust.md)
- [Go](dev/go.md)
- [Swift](dev/swift.md)
- [AssemblyScript](dev/as.md)
- [Kotlin](dev/kotlin.md)
- [Grain](dev/grain.md)
- [Python](dev/python.md)

- [Rust](dev/rust.md)
- [Call Rust functions](dev/rust/bindgen.md)
- [Access OS services](dev/rust/wasi.md)
- [Tensorflow](dev/rust/tensorflow.md)
- [Simple HTTP client & server](dev/rust/networking.md)
- [Non-blocking network apps](dev/rust/networking-nonblocking.md)
- [Command interface](dev/rust/command.md)
- [JavaScript](dev/js.md)
- [Getting started](dev/js/quickstart.md)
- [Networking sockets](dev/js/networking.md)
- [Fetch](dev/js/fetch.md)
- [Tensorflow](dev/js/tensorflow.md)
- [React SSR](dev/js/ssr.md)
- [ES6 module](dev/js/es6.md)
- [NodeJS &amp; NPM module](dev/js/npm.md)
- [Use Rust to implement JS API](dev/js/rust.md)
- [Go](dev/go.md)
- [Swift](dev/swift.md)
- [AssemblyScript](dev/as.md)
- [Kotlin](dev/kotlin.md)
- [Grain](dev/grain.md)
- [Python](dev/python.md)

- [Embed WasmEdge functions](embed.md)
- [C SDK](embed/c.md)
- [API references](embed/c/ref.md)
Expand Down
33 changes: 19 additions & 14 deletions docs/book/en/src/dev/js/networking.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Async networking sockets
# Async networking apps

The QuickJS WasmEdge Runtime supports the WasmEdge [networking socket extension](https://github.com/second-state/wasmedge_wasi_socket) so that the JavaScript programs can make HTTP connections to the Internet. This article will show you both [HTTP Client](https://github.com/second-state/wasmedge-quickjs/blob/main/example_js/wasi_http_client.js) and [HTTP Server](https://github.com/second-state/wasmedge-quickjs/blob/main/example_js/wasi_http_echo.js) examples.

> The networking API in WasmEdge is non-blocking and hence allows asynchronous I/O intensive applications. When the network request handler is making an outbound request and waiting for a response, the app can handle another incoming request. That allows the single-threaded application to handle multiple multiple concurrent requests.
> The networking API in WasmEdge is non-blocking and hence supports asynchronous I/O intensive applications. With this API, the JavaScript program can open multiple connections concurrently. It polls those connections, or registers async callback functions, to process data whenever data comes in, without waiting for any one connection to complete its data transfer. That allows the single-threaded application to handle multiple multiple concurrent requests.
## A JavaScript networking client example

Expand All @@ -27,7 +27,7 @@ async function get_test() {
}
```

The program can do other tasks while waiting for the server to respond. Once the server responds, the `handle_response()` function is called asynchronously to process the response and to print out the content.
The program can open multiple requests while waiting for the servers to respond. Once a server responds, the `handle_response()` function is called asynchronously to process the response and to print out the content.

```javascript
async function handle_response(s) {
Expand Down Expand Up @@ -91,32 +91,37 @@ Below is an example of JavaScript running a TCP server listening at port 8000. T
import * as net from 'wasi_net';

async function handle_client(cs) {
while (true) {
try {
try {
while (true) {
let d = await cs.read();
if (d.byteLength <= 0) {
if (d == undefined || d.byteLength <= 0) {
break;
}
let s = newStringFromUTF8(d);
cs.write('echo:' + s);
} catch (e) {
print(e);
}
} catch (e) {
print(e);
}
}

async function server_start() {
let s = new net.WasiTcpServer(8000);
for (var i = 0; i < 100; i++) {
let cs = await s.accept();
handle_client(cs);
print('listen 8000 ...');
try {
let s = new net.WasiTcpServer(8000);
for (var i = 0; i < 100; i++) {
let cs = await s.accept();
handle_client(cs);
}
} catch (e) {
print(e)
}
}

server_start();
```

The `server_start()` function starts the server at port 8000. When a request comes in, it passes to the `handle_client()` function to process it asynchronously. That means while the app is sending back the response, it could start handling the next incoming request.
The `server_start()` function starts the server at port 8000. When a request comes in, it accepts immediately and calls the `handle_client()` function to process it asynchronously when the request data is received later. While the `handle_client()` is waiting for the data to arrive from the network, the app could accept another request concurrently.

To run the JavaScript in the WasmEdge runtime, you can do this on the CLI. Since it is a server, you should run it in the background.

Expand Down Expand Up @@ -195,7 +200,7 @@ async function server_start() {
server_start();
```

The `server_start()` function starts the server at port 8000. When a request comes in, it passes to the `handle_client()` function to process the request. Once the request is validated as an HTTP request, the handler function in turn calls `handle_req()` to parse the fields in the HTTP request, compose a HTTP reponse, and then send the response back asynchronously. That means while the app is sending back the response, it could start handling the next incoming request.
The `server_start()` function starts the server at port 8000. When a request comes in, it accepts immediately and calls the `handle_client()` async function to process the request data when the data is received later. Once the request is validated as an HTTP request, the handler function in turn calls `handle_req()` to parse the fields in the HTTP request, compose a HTTP reponse, and then send the response back. While the program is waiting for the request data to arrive from the network, it can accept another request concurrently.

To run the JavaScript in the WasmEdge runtime, you can do this on the CLI. Since it is a server, you should run it in the background.

Expand Down
7 changes: 3 additions & 4 deletions docs/book/en/src/dev/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ Instead, you will probably need to use a [language SDK from WasmEdge](../../embe
to call the function, pass call parameters, and receive return values.
Below are some SDK examples for complex call parameters and return values.

* [Use wasm-bindgen in a Node.js host app](../embed/node.md#more-examples)
* [Use wasm-bindgen in a Go host app](../embed/go/bindgen.md)
* [Use wasmedge-bindgen in a Go host app](../embed/go/function.md)
* [Use direct memory passing in a Go host app](../embed/go/memory.md)

## Improve performance
Expand Down Expand Up @@ -117,6 +116,6 @@ $ wasmedge --reactor add.wasm add 2 2

* [Access OS services via WASI](rust/wasi.md) shows how the WebAssembly program can access the underlying OS services, such as file system and environment variables.
* [Tensorflow](rust/tensorflow.md) shows how to create Tensorflow-based AI inference applications for WebAssembly using the WasmEdge TensorFlow Rust SDK.
* [Networking socket](rust/networking.md) shows how to create networking applications for WebAssembly using the WasmEdge networking socket Rust SDK.
* [Simple networking socket](rust/networking.md) shows how to create simple HTTP client and server applications using the WasmEdge networking socket Rust SDK.
* [Non-blocking networking socket](rust/networking-nonblocking.md) shows how to create a high-performance non-blocking networking applications with concurrent open connections using the WasmEdge networking socket Rust SDK.
* [Command interface](rust/command.md) shows how to create native command applications for WebAssembly using the Wasmedge command interface Rust SDK.
* [Bindgen and rustwasmc](rust/bindgen.md) shows how to use the `rustwasmc` toolchain to compile Rust functions into WebAssembly, and then pass complex call parameters to the function from an external host application.
72 changes: 14 additions & 58 deletions docs/book/en/src/dev/rust/bindgen.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,22 @@
# Bindgen and rustwasmc
# Call Rust functions

**NOTE: This has been deprecated. We recommend using [wasmedge-bindgen](https://github.com/second-state/wasmedge-bindgen) when calling WebAssembly functions from another application (e.g., from [Go](https://wasmedge.org/book/en/embed/go/function.html)).**
If your Rust program has a `main()` function, you could compile it into a WASM bytecode file, and run it using the `wasmedge` CLI tool as a standalone application. However, a far more common use case is to compile a Rust function into a WASM bytecode file, and then call it from a host application. That is known as an embedded WASM function. The host application uses WasmEdge language SDKs (e.g., [Go](../../embed/go.md), [Rust](../../embed/rust.md), [C](../../embed/c.md), [Python](../../embed/go.md) and [Node.js](../../embed/node.md)) to call those WASM functions compiled from Rust source code.

---
All the WasmEdge host language SDKs support simple function calls. However, the WASM spec only supports a few simple data types as call parameters and return values. The `wasmedge-bindgen` crate would transform call parameters and return values of Rust functions into simple integer types when the Rust function is compiled into WASM. For example, a string is automatically converted into two integers, a memory address and a length, which can be handled by the standard WASM spec. It is very easy to do this in Rust source code. Just annotate your function with the `#[wasmedge-bindgen]` macro. You can compile the annotated Rust code using the standard Rust compiler toolchain (e.g., the latest `Cargo`).

The [rustwasmc](https://github.com/second-state/rustwasmc) tool is inspired by the wasm-pack project but is optimized for edge cloud and device applications. Specifically, it supports the [WasmEdge](https://github.com/WasmEdge/WasmEdge) WebAssembly runtime.
```rust
use wasmedge_bindgen::*;
use wasmedge_bindgen_macro::*;

One of the key features of `rustwasmc` over the standard `wasm32-wasi` compiler target is that `rustwasmc` processes compiled Rust functions using the `wasm-bindgen` tool.
By default, WebAssembly functions only support a few simple data types as input call arguments. Tools like `wasm-bindgen` turn WebAssembly function arguments into memory pointers, and allow host applications to pass complex arguments, such as strings and arrays, to WebAssembly functions.
WasmEdge's [Node.js SDK](../../embed/node.md) and [Go SDK](../../embed/go.md) both support `wasm-bindgen`, allowing JavaScript and Go programs to call WebAssembly function with complex call arguments.

> At this time, we require Rust compiler version 1.50 or less in order for WebAssembly functions to work with `wasm-bindgen` and `rustwasmc`. We will [catch up to the latest Rust compiler](https://github.com/WasmEdge/WasmEdge/issues/264) version once the Interface Types spec is finalized and supported.
## Prerequisites

The `rustwasmc` depends on the Rust cargo toolchain to compile Rust source code to WebAssembly. You must have [Rust installed](https://www.rust-lang.org/tools/install) on your machine.

```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
rustup override set 1.50.0
#[wasmedge_bindgen]
pub fn say(s: String) -> Result<Vec<u8>, String> {
let r = String::from("hello ");
return Ok((r + s.as_str()).as_bytes().to_vec());
}
```

## Install

The easiest way to install [rustwasmc](https://github.com/second-state/rustwasmc) is to use its installer.
Of course, once the above Rust code is compiled into WASM, the function `say()` no longer takes the `String` parameter nor returns the `Vec<u8>`. So, the caller (i.e., the host application) must also deconstruct the call parameter into the memory pointer first before the call, and assemble the return value from the memory pointer after the call. These actions can be handled automagically by the WasmEdge language SDKs. To see a complete example, including the Rust WASM function and the Go host application, check out our tutorial in the Go SDK documentation.

```bash
curl https://raw.githubusercontent.com/second-state/rustwasmc/master/installer/init.sh -sSf | sh
```

Alternatively, you can [install using the NPM](https://github.com/second-state/rustwasmc#install) if you'd like.

## Usage

To build [Rust functions for Node.js](../../embed/node.md) applications, use the following command. See a [template application](https://github.com/second-state/wasmedge-nodejs-starter).

```bash
rustwasmc build
```

Use the `--enable-ext` flag to compile Rust programs that use WASI extensions, such as WasmEdge's storage and [Tensorflow](tensorflow.md) APIs. The `rustwasmc` will generates the compiled WebAssembly bytecode program for the `wasmedge-extensions` Node.js module instead of the `wasmedge-core` module in this case.

```bash
rustwasmc build --enable-ext
```

## Support AOT

A key feature of the WasmEdge runtime is its support for Ahead-of-Time (AOT) compilers. When you run WebAssembly programs in Node.js `wasmedge-core` and `wasmedge-extensions` add-ons, you typically do not need to worry about it as the add-on handles AOT compilation transparently. However, in some cases, you do want the `rustwasmc` to compile and generate native code for the program.
Then, use the commands below to bring your operating system up to date with the latest developer tools. The commands here are tested on Ubuntu 20.04.

```bash
sudo apt-get update
sudo apt-get -y upgrade
sudo apt install build-essential curl wget git vim libboost-all-dev llvm-dev liblld-10-dev
```

Now, you can build the `.so` files for the AOT native target like the following.

```bash
rustwasmc build --enable-aot
```
**[A complete wasmedge-bindgen example in Rust (WASM) and Go (host)](../../embed/go/function.md)**

Enjoy coding!
Of course, the developer could choose to do `wasmedge-bindgen`'s work by hand and pass a memory pointer directly. If you are interested in this approach to call Rust compiled WASM functions, check out our [examples in the Go SDK](../../embed/go/memory.md).
Loading

0 comments on commit 4e2fb5d

Please sign in to comment.