diff --git a/pages/docs/language-guide/rust/tutorials/_meta.json b/pages/docs/language-guide/rust/tutorials/_meta.json
index 3799047..df7fcca 100644
--- a/pages/docs/language-guide/rust/tutorials/_meta.json
+++ b/pages/docs/language-guide/rust/tutorials/_meta.json
@@ -1,6 +1,7 @@
{
- "wasix-axum": "Wasix with Axum",
- "wasix-reqwest": "Wasix with Reqwest",
+ "wasix-axum": "WASIX with Axum",
+ "wasix-reqwest": "WASIX with Reqwest",
"condvar": "Condition variables",
- "threading": "Threading with Wasix"
+ "threading": "Threading with WASIX",
+ "wasix-grpc": "WASIX with gRPC"
}
diff --git a/pages/docs/language-guide/rust/tutorials/wasix-grpc.mdx b/pages/docs/language-guide/rust/tutorials/wasix-grpc.mdx
new file mode 100644
index 0000000..f245f1c
--- /dev/null
+++ b/pages/docs/language-guide/rust/tutorials/wasix-grpc.mdx
@@ -0,0 +1,664 @@
+import { Steps } from "nextra-theme-docs";
+import { Callout, FileTree } from "nextra-theme-docs";
+import CliVersionCallout from "../../../../../components/CliVersionCallout.mdx";
+
+# WASIX with gRPC
+
+## Introduction
+
+This is a tutorial on how to use gRPC with https in WASIX. We will use the [tonic](https://github.com/hyperium/tonic) crate to implement a simple gRPC server and client in Rust.
+
+
+ This tutorial does not focuses on instantiating gRPC with rust but is rather
+ focused on getting WASIX compatability in gRPC with tonic.
+
+
+## Prerequisites
+
+
+
+The project requires the following tools to be installed on your system:
+
+- [Rust](https://www.rust-lang.org/tools/install)
+- [Wasmer](https://docs.wasmer.io/install)
+- [WASIX](/docs/language-guide/rust/installation)
+
+## Project Description
+
+We’ll be following [tls_rustls](https://github.com/hyperium/tonic/tree/master/examples/src/tls_rustls) example from tonic’s official repo.
+This example implements a unary hello world example with https support.
+
+
+### Project Setup
+
+Let's create a new project with cargo.
+
+```shell
+$ cargo new --bin wasix-grpc
+ Created binary (application) `wasix-grpc` package
+```
+
+Your `wasix-grpc` directory structure should look like this:
+
+
+
+
+
+
+
+
+
+
+
+As we'll place both **server** and the **client** in the same project. We won't be needing the `main.rs` file. So, let's delete it.
+
+```shell
+$ rm src/main.rs
+```
+
+Rather we'd need a `server.rs` and a `client.rs` file. So, let's create them.
+
+```shell
+$ touch src/server.rs src/client.rs
+```
+
+Both of these will be our entry points for the server and the client respectively. We'll also need a `proto` file to define our service. So, let's create a `proto` directory and a `hello.proto` file inside it.
+
+```shell
+$ mkdir proto
+$ touch proto/helloworld.proto
+```
+
+Let's also add the following dependencies to our `Cargo.toml` file.
+
+```toml
+[dependencies]
+tonic = { version = "0.9", features = ["tls"] }
+prost = "0.11"
+tokio = { version = "=1.24.2", default-features = false, features = [
+ "full",
+] }
+
+tokio-stream = "0.1.14"
+
+hyper-rustls = { version="0.24.1", features = [
+ "http2",
+] }
+
+tokio-rustls = "0.24.1"
+hyper = "0.14.27"
+tower = "0.4.13"
+http-body = "0.4.5"
+tower-http = "0.4.3"
+rustls-pemfile = "1.0.3"
+rustls-native-certs = "0.6.3"
+
+[build-dependencies]
+tonic-build = "0.9"
+```
+
+
+ The `build-dependencies` section is required to compile the proto file.
+
+
+We need to also define our entry points in the `Cargo.toml` file.
+
+```toml
+[[bin]] # Bin to run the HelloWorld gRPC server
+name = "helloworld-server"
+path = "src/server.rs"
+
+[[bin]] # Bin to run the HelloWorld gRPC client
+name = "helloworld-client"
+path = "src/client.rs"
+```
+
+While we're at it let's also add `build.rs` for compiling the proto file.
+
+```shell
+$ touch build.rs
+```
+
+```rust
+// build.rs
+fn main() -> Result<(), Box> {
+ tonic_build::compile_protos("proto/helloworld.proto")?;
+ Ok(())
+}
+```
+
+Okay, we're all set to start writing our proto file and then our server & client.
+
+But first let's see our directory structure.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+### Proto file
+
+Let's define our service in the `proto/helloworld.proto` file.
+
+```proto
+// proto/helloworld.proto
+
+syntax = "proto3";
+package helloworld;
+
+service Greeter {
+ rpc Send(HelloRequest) returns (HelloReply) {}
+
+}
+
+message HelloRequest {
+ string name = 1;
+}
+
+message HelloReply {
+ string message = 1;
+}
+```
+
+### Wiring up client and server
+
+Let's start with the server.
+
+```rust
+// src/server.rs
+use tonic::{transport::Server, Request, Response, Status};
+
+use hello_world::greeter_server::{Greeter, GreeterServer};
+use hello_world::{HelloReply, HelloRequest};
+
+pub mod hello_world {
+ tonic::include_proto!("helloworld"); // The string specified here must match the proto package name
+}
+
+#[derive(Debug, Default)]
+pub struct MyGreeter {}
+
+#[tonic::async_trait]
+impl Greeter for MyGreeter {
+ async fn send(
+ &self,
+ request: Request,
+ ) -> Result, Status> {
+ println!("Got a request: {:?}", request);
+
+ let reply = HelloReply {
+ message: format!("Hello {}!", request.into_inner().name),
+ };
+
+ Ok(Response::new(reply))
+ }
+}
+
+#[tokio::main]
+async fn main() -> Result<(), Box> {
+ let addr = "127.0.0.1:50051".parse()?;
+ let greeter = MyGreeter::default();
+
+ println!("Server listening on {}", addr);
+
+ Server::builder()
+ .add_service(GreeterServer::new(greeter))
+ .serve(addr)
+ .await?;
+
+ Ok(())
+}
+```
+
+Now, let's write our client.
+
+```rust
+// src/client.rs
+use hello_world::greeter_client::GreeterClient;
+use hello_world::HelloRequest;
+
+pub mod hello_world {
+ tonic::include_proto!("helloworld");
+}
+
+#[tokio::main]
+async fn main() -> Result<(), Box> {
+ let mut client = GreeterClient::connect("http://127.0.0.1:50051").await?;
+
+ let request = tonic::Request::new(HelloRequest {
+ name: "Tonic".into(),
+ });
+
+ let response = client.say_hello(request).await?;
+
+ println!("RESPONSE={:?}", response);
+
+ Ok(())
+}
+```
+
+#### Testing the server and client
+
+Let's test our server and client.
+
+```shell
+$ cargo run --bin helloworld-server
+ Finished dev [unoptimized + debuginfo] target(s) in 0.14s
+ Running `target/debug/helloworld-server`
+Server listening on 127.0.0.1:50051
+```
+
+Now, in another terminal run the client.
+
+```shell
+$ cargo run --bin helloworld-client
+ Finished dev [unoptimized + debuginfo] target(s) in 0.15s
+ Running `target/debug/helloworld-client`
+RESPONSE=Response \{ metadata: MetadataMap { headers: {"content-type": "application/grpc", "date": "Mon, 28 Aug 2023 12:54:16 GMT", "grpc-status": "0"} }, message: HelloReply { message: "Hello Tonic!" }, extensions: Extensions }
+```
+
+### Adding in **https** support
+
+For adding **https** support we need server and client certificates. You can get them from [tonic's repo](https://github.com/hyperium/tonic/tree/master/examples/data/tls) or you can generate them yourself.
+
+Let's place the certificates in a `tls` directory.
+
+```shell
+$ mkdir tls
+```
+
+Copy the `ca.pem`, `server.pem` and `server.key` files from [tonic's repo](https://github.com/hyperium/tonic/tree/master/examples/data/tls) to the `tls` directory.
+
+
+ **Certificates Infomation**:
+
+ - `ca.pem` - Client Certificate
+ - `server.pem` - Server certificate
+ - `server.key` - Server private key
+
+
+
+Modify the `server.rs` file to use the certificates.
+
+> Note: I'm just copy pasting most of the code from the tonic repo's [tls_rustls](https://github.com/hyperium/tonic/tree/master/examples/src/tls_rustls) example and modifying it according to our proto file.
+
+```rust
+use hyper::server::conn::Http;
+use tokio_rustls::rustls::{OwnedTrustAnchor, RootCertStore, ServerConfig};
+use tonic::{transport::Server, Request, Response, Status};
+
+use hello_world::greeter_server::Greeter;
+use hello_world::{HelloReply, HelloRequest};
+
+use tokio::sync::mpsc;
+use tokio_stream::{wrappers::ReceiverStream, Stream, StreamExt};
+
+use std::error::Error;
+use std::io::ErrorKind;
+use std::pin::Pin;
+use std::time::Duration;
+
+use std::sync::Arc;
+use tokio::net::TcpListener;
+use tokio_rustls::{
+ rustls::{Certificate, PrivateKey},
+ TlsAcceptor,
+};
+use tower_http::ServiceBuilderExt;
+
+pub mod hello_world {
+ tonic::include_proto!("helloworld"); // The string specified here must match the proto package name
+}
+
+#[derive(Debug, Default)]
+pub struct MyGreeter {}
+
+#[tonic::async_trait]
+impl Greeter for MyGreeter {
+ async fn send(&self, request: Request) -> Result, Status> {
+ Ok(Response::new(HelloReply {
+ message: format!("hello {}", request.get_ref().name),
+ }))
+ }
+}
+#[tokio::main]
+async fn main() -> Result<(), Box> {
+ let data_dir = if cfg!(target_os = "wasi") {
+ std::env::current_dir()?
+ } else {
+ std::path::PathBuf::from(std::env!("CARGO_MANIFEST_DIR"))
+ };
+ let certs = {
+ let fd = std::fs::File::open(data_dir.join("tls/server.pem"))?;
+ let mut buf = std::io::BufReader::new(&fd);
+ rustls_pemfile::certs(&mut buf)?
+ .into_iter()
+ .map(Certificate)
+ .collect()
+ };
+ let key = {
+ let fd = std::fs::File::open(data_dir.join("tls/server.key"))?;
+ let mut buf = std::io::BufReader::new(&fd);
+ rustls_pemfile::pkcs8_private_keys(&mut buf)?
+ .into_iter()
+ .map(PrivateKey)
+ .next()
+ .unwrap()
+ };
+
+ let mut tls = ServerConfig::builder()
+ .with_safe_defaults()
+ .with_no_client_auth()
+ .with_single_cert(certs, key)?;
+ tls.alpn_protocols = vec![b"h2".to_vec()];
+
+ let server = MyGreeter::default();
+
+ let svc = Server::builder()
+ .add_service(hello_world::greeter_server::GreeterServer::new(server))
+ .into_service();
+
+ let mut http = Http::new();
+ http.http2_only(true);
+
+ let listener = TcpListener::bind("127.0.0.1:50051").await?;
+ let tls_acceptor = TlsAcceptor::from(Arc::new(tls));
+
+ println!("Server listening on {}", listener.local_addr()?);
+
+ loop {
+ let (conn, addr) = match listener.accept().await {
+ Ok(incoming) => incoming,
+ Err(e) => {
+ eprintln!("Error accepting connection: {}", e);
+ continue;
+ }
+ };
+
+ let http = http.clone();
+ let tls_acceptor = tls_acceptor.clone();
+ let svc = svc.clone();
+
+ tokio::spawn(async move {
+ let mut certificates = Vec::new();
+
+ let conn = tls_acceptor
+ .accept_with(conn, |info| {
+ if let Some(certs) = info.peer_certificates() {
+ for cert in certs {
+ certificates.push(cert.clone());
+ }
+ }
+ })
+ .await
+ .unwrap();
+
+ let svc = tower::ServiceBuilder::new()
+ .add_extension(Arc::new(ConnInfo { addr, certificates }))
+ .service(svc);
+
+
+ http.serve_connection(conn, svc)
+ .await
+ .map_err(|e| {
+ eprintln!("Error serving connection: {}", e);
+ e
+ })
+ .unwrap();
+ });
+ }
+}
+
+#[derive(Debug)]
+struct ConnInfo {
+ addr: std::net::SocketAddr,
+ certificates: Vec,
+}
+```
+
+Now the client.
+
+```rust
+
+use std::{sync::Arc, time::Duration};
+
+use hello_world::greeter_client::GreeterClient;
+use hello_world::HelloRequest;
+
+use http_body::{combinators::UnsyncBoxBody, Body};
+use hyper::{body::Bytes, client::HttpConnector, Client, Request, Uri};
+use hyper_rustls::HttpsConnector;
+use tokio_rustls::rustls::{ClientConfig, ConfigBuilder, OwnedTrustAnchor, RootCertStore};
+use tokio_stream::{Stream, StreamExt};
+use tonic::{
+ body::BoxBody,
+ client::GrpcService,
+ transport::{Channel, ClientTlsConfig},
+ Status,
+};
+use tower::{util::MapRequest, ServiceExt};
+
+pub mod hello_world {
+ tonic::include_proto!("helloworld");
+}
+
+async fn say_hello(client: &mut GreeterClient)
+where
+ T: tonic::client::GrpcService + Send + 'static,
+ T::ResponseBody: Body + Send + 'static,
+ ::Error: Into> + Send,
+{
+ let request = tonic::Request::new(HelloRequest {
+ name: "Alice".into(),
+ });
+
+ let response = client.send(request).await.unwrap();
+
+ println!("RESPONSE={:?}", response);
+}
+
+
+#[tokio::main]
+async fn main() -> Result<(), Box> {
+ let data_dir = if cfg!(target_os = "wasi") {
+ std::env::current_dir()?
+ } else {
+ std::path::PathBuf::from(std::env!("CARGO_MANIFEST_DIR"))
+ };
+ let fd = std::fs::File::open(data_dir.join("tls/ca.pem"))?;
+
+ let mut roots = RootCertStore::empty();
+
+ let mut buf = std::io::BufReader::new(&fd);
+ let certs = rustls_pemfile::certs(&mut buf)?;
+ roots.add_parsable_certificates(&certs);
+
+ let tls = ClientConfig::builder()
+ .with_safe_defaults()
+ .with_root_certificates(roots)
+ .with_no_client_auth();
+
+ let mut http = HttpConnector::new();
+ http.enforce_http(false);
+
+ let connector = tower::ServiceBuilder::new()
+ .layer_fn(move |s| {
+ let tls = tls.clone();
+
+ hyper_rustls::HttpsConnectorBuilder::new()
+ .with_tls_config(tls)
+ .https_or_http()
+ .enable_http2()
+ .wrap_connector(s)
+ })
+ .map_request(|_: Uri| Uri::from_static("https://127.0.0.1:50051"))
+ .service(http);
+ // .boxed_clone();
+
+ let client = hyper::Client::builder().build(connector);
+
+ // Using `with_origin` will let the codegenerated client set the `scheme` and
+ // `authority` from the provided `Uri`.
+ let uri = Uri::from_static("https://example.com");
+
+ let mut client = GreeterClient::with_origin(client, uri);
+
+ say_hello(&mut client).await;
+
+ Ok(())
+}
+```
+
+#### Testing the server and client
+
+In a terminal run the server.
+
+```shell
+$ cargo run --bin helloworld-server
+ Finished dev [unoptimized + debuginfo] target(s) in 1.77s
+ Running `target/debug/helloworld-server`
+Server listening on 127.0.0.1:50051
+```
+
+Now, in another terminal run the client.
+
+```shell
+$ cargo run --bin helloworld-client
+ Finished dev [unoptimized + debuginfo] target(s) in 2.55s
+ Running `target/debug/helloworld-client`
+RESPONSE=Response \{ metadata: MetadataMap { headers: {"content-type": "application/grpc", "date": "Mon, 28 Aug 2023 13:29:27 GMT", "grpc-status": "0"} }, message: HelloReply { message: "hello Alice" }, extensions: Extensions }
+```
+
+Yup, it works.
+
+### WASIX Compatability
+
+For compiling our project to wasix, we need to pin and patch some dependencies in our `Cargo.toml` file.
+
+```toml
+[dependencies]
+tonic = { version = "0.9", features = ["tls"] }
+prost = "0.11"
+tokio = { version = "=1.24.2", git = "https://github.com/wasix-org/tokio.git", branch = "epoll", default-features = false, features = [
+ "full",
+] } # 👈🏼 pinned to wasix fork
+libc = { version = "0.2.139", git = "https://github.com/wasix-org/libc.git", branch = "master" } # 👈🏼 pinned to wasix fork
+tokio-stream = "0.1.14"
+hyper-rustls = { git = "https://github.com/wasix-org/hyper-rustls.git", branch = "main", features = [
+ "http2",
+] } # 👈🏼 pinned to wasix fork
+tokio-rustls = { version = "0.24.1", git = "https://github.com/wasix-org/tokio-rustls.git", branch = "main" } # 👈🏼 pinned to wasix fork
+hyper = { git = "https://github.com/wasix-org/hyper.git", branch = "v0.14.27" } # 👈🏼 pinned to wasix fork
+tower = "0.4.13"
+http-body = "0.4.5"
+tower-http = { version = "0.4.3", features = ["util", "add-extension"] }
+rustls-pemfile = "1.0.3"
+rustls-native-certs = { path = "/Volumes/Work/Projects/Rust/rustls-native-certs" } # 👈🏼 pinned to wasix fork
+
+[build-dependencies]
+tonic-build = "0.9"
+
+[patch.crates-io]
+rustls-native-certs = { git = "https://github.com/wasix-org/rustls-native-certs.git" } # 👈🏼 patched to wasix fork
+socket2 = { git = "https://github.com/wasix-org/socket2.git", branch = "v0.4.9" } # 👈🏼 patched to wasix fork
+tokio = { git = "https://github.com/wasix-org/tokio.git", branch = "epoll" } # 👈🏼 patched to wasix fork
+hyper = { git = "https://github.com/wasix-org/hyper.git", branch = "v0.14.27" } # 👈🏼 patched to wasix fork
+ring = { git = "https://github.com/wasix-org/ring.git", branch = "wasix" } # 👈🏼 patched to wasix fork
+rustls = { git = "https://github.com/wasix-org/rustls.git", branch = "v0.21.5" } # 👈🏼 patched to wasix fork
+```
+
+For a list of all of our forks, you can checkout the [patched repos](../patched-repos) page.
+
+#### Compiling the project to WASIX
+
+```shell
+$ cargo wasix build --release
+...
+warning: `wasix-grpc` (bin "helloworld-server") generated 2 warnings (run `cargo fix --bin "helloworld-server"` to apply 1 suggestion)
+warning: `wasix-grpc` (bin "helloworld-client") generated 6 warnings (run `cargo fix --bin "helloworld-client"` to apply 3 suggestions)
+ Finished release [optimized] target(s) in 26.41s
+info: Post-processing WebAssembly files
+ Optimizing with wasm-opt
+ Optimizing with wasm-opt
+```
+
+#### Testing the server and client
+
+
+In the client and server code you'll find this snippet.
+```rust
+let data_dir = if cfg!(target_os = "wasi") {
+ std::env::current_dir()?
+} else {
+ std::path::PathBuf::from(std::env!("CARGO_MANIFEST_DIR"))
+};
+```
+This code maps the `data_dir` to current directory if the `target_os` is **wasi**. This is **important** because _CARGO_MANIFEST_DIR_ is not available in WASIX.
+
+
+##### Running the server
+
+```shell
+$ wasmer run target/wasm32-wasmer-wasi/release/helloworld-server.wasm --net --mapdir /tls:./tls
+Server listening on 127.0.0.1:50051
+```
+
+##### Running the client
+
+```shell
+$ wasmer run target/wasm32-wasmer-wasi/release/helloworld-client.wasm --net --mapdir /tls:./tls
+RESPONSE=Response \{ metadata: MetadataMap { headers: {"content-type": "application/grpc", "date": "Mon, 28 Aug 2023 15:01:09 GMT", "grpc-status": "0"} }, message: HelloReply { message: "hello Alice" }, extensions: Extensions }
+```
+
+**Yup, works the same.**
+
+###### Flags Information
+
+- `--net` - enables networking support
+- `--mapdir /tls:./tls` - maps the `/tls` directory in the WASIX filesystem to the `./tls` directory in the host filesystem.
+
+To know more about the flags run `wasmer run --help`.
+
+
+
+### 🤸🏼 Exercise Time
+
+- Try to implement a server streaming example with WASIX.
+- Try to implement a client streaming example with WASIX.
+- Try to implement a bidirectional streaming example with WASIX.
+
+# Conclusion
+
+In this tutorial we learnt
+
+- how to use gRPC with https in WASIX. We used the [tonic](https://crates.io/crates/tonic) crate to implement a simple gRPC server and client in Rust
+- how to compile the project to WASIX
+- how to run the gRPC server and client in WASIX
+- how to use the `--net` and `--mapdir` flags in Wasmer to enable networking support and map directories respectively.
+
+For the full example code, you can checkout the repository below.
+
+import { Card, Cards } from "nextra-theme-docs";
+
+
+
+
+ }
+ title="wasix-rust-examples/wasix-grpc"
+ href="https://github.com/wasix-org/wasix-rust-examples/tree/main/wasix-grpc"
+/>