This is an automated email from the ASF dual-hosted git repository.

albumenj pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo-website.git


The following commit(s) were added to refs/heads/master by this push:
     new e9d4ce8b1d9 Improve rust documents (#1530)
e9d4ce8b1d9 is described below

commit e9d4ce8b1d92e67d85d60b0cfc6f437f47561b84
Author: Robert LU <[email protected]>
AuthorDate: Thu Sep 29 11:44:53 2022 +0800

    Improve rust documents (#1530)
    
    * improve rust quick-start
    
    * add rust-sdk/java-interoperability
    
    * add rust to toc
---
 .../zh/docs3-v2/rust-sdk/java-interoperability.md  |  70 ++++
 content/zh/docs3-v2/rust-sdk/quick-start.md        | 432 +++++++++++++++++++--
 content/zh/overview/mannual/Rust.md                |  13 +
 content/zh/overview/mannual/_index.md              |  52 ++-
 4 files changed, 519 insertions(+), 48 deletions(-)

diff --git a/content/zh/docs3-v2/rust-sdk/java-interoperability.md 
b/content/zh/docs3-v2/rust-sdk/java-interoperability.md
new file mode 100644
index 00000000000..297c5c585db
--- /dev/null
+++ b/content/zh/docs3-v2/rust-sdk/java-interoperability.md
@@ -0,0 +1,70 @@
+---
+type: docs
+title: "Rust和Java互相调用"
+linkTitle: "Rust和Java互相调用"
+weight: 2
+description: "使用 Rust 调用 Java 开发的 Dubbo 服务。"
+---
+
+## 1 前置条件
+- 安装 [Rust](https://rustup.rs/) 开发环境
+- 安装 [protoc](https://grpc.io/docs/protoc-installation/) 工具
+- 安装 Java 开发环境
+
+## 2 运行示例 Java 版本的 Dubbo provider
+
+Java 版本的 Dubbo provider 
示例源码见<https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-triple>。
+
+Clone 源代码、编译构建,并运行 provider:
+
+```sh
+$ # clone 源代码
+$ git clone https://github.com/apache/dubbo-samples.git
+$ cd dubbo-samples/dubbo-samples-triple/
+
+$ # 构建
+$ mvn clean compile package -DskipTests
+
+$ # 运行 provider
+$ java -Dprovider.port=8888 -jar ./target/dubbo-samples-triple-1.0-SNAPSHOT.jar
+# ……省略部分日志
+Dubbo triple stub server started, port=8888
+```
+
+[Java 
侧的接口定义](https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-triple/src/main/proto/greeter.proto)
+
+## 3 运行 Rust 版本的 Dubbo consumer
+
+Rust 版本的 Dubbo consumer 
示例源码见<https://github.com/apache/dubbo-rust/tree/main/examples/greeter>。
+
+Clone 源代码、编译构建,并运行 consumer:
+
+```sh
+$ # clone 源代码
+$ git clone https://github.com/apache/dubbo-rust.git
+$ cd dubbo-rust/examples/greeter/
+
+$ # 构建
+$ cargo build
+
+$ # 运行 consumer,调用provider
+$ ../../target/debug/greeter-client
+# unary call
+Response: GreeterReply { message: "hello, dubbo-rust" }
+# client stream
+client streaming, Response: GreeterReply { message: "hello client streaming" }
+# bi stream
+parts: Metadata { inner: {"content-type": "application/grpc", "date": "Wed, 28 
Sep 2022 23:54:56 GMT"} }
+reply: GreeterReply { message: "server reply: \"msg1 from client\"" }
+reply: GreeterReply { message: "server reply: \"msg2 from client\"" }
+reply: GreeterReply { message: "server reply: \"msg3 from client\"" }
+trailer: Some(Metadata { inner: {"grpc-message": "poll trailer successfully.", 
"grpc-accept-encoding": "gzip,identity", "content-type": "application/grpc", 
"grpc-status": "0"} })
+# server stream
+parts: Metadata { inner: {"content-type": "application/grpc", "date": "Wed, 28 
Sep 2022 23:54:56 GMT"} }
+reply: GreeterReply { message: "msg1 from server" }
+reply: GreeterReply { message: "msg2 from server" }
+reply: GreeterReply { message: "msg3 from server" }
+trailer: Some(Metadata { inner: {"content-type": "application/grpc", 
"grpc-message": "poll trailer successfully.", "grpc-accept-encoding": 
"gzip,identity", "grpc-status": "0"} })
+```
+
+[Rust侧的接口定义](https://github.com/apache/dubbo-rust/blob/main/examples/greeter/proto/greeter.proto)
diff --git a/content/zh/docs3-v2/rust-sdk/quick-start.md 
b/content/zh/docs3-v2/rust-sdk/quick-start.md
index 48486ffa96f..a7b15b3a0ae 100644
--- a/content/zh/docs3-v2/rust-sdk/quick-start.md
+++ b/content/zh/docs3-v2/rust-sdk/quick-start.md
@@ -6,75 +6,453 @@ weight: 1
 description: "使用 Rust 快速开发 Dubbo 服务。"
 ---
 
-请在此查看完整 [示例](https://github.com/apache/dubbo-rust)。
+请在此查看完整 [示例](https://github.com/apache/dubbo-rust/tree/main/examples/greeter)。
 
 ## 1 前置条件
 - 安装 [Rust](https://rustup.rs/) 开发环境
+- 安装 [protoc](https://grpc.io/docs/protoc-installation/) 工具
 
 ## 2 使用 IDL 定义 Dubbo 服务
 
-HelloWorld 服务定义如下,包含一个 Request - Response 模型的 Unary 服务。
+Greeter 服务定义如下,包含一个 Unary、Client stream、Server stream、Bidirectional stream 模型的 
Dubbo 服务。
 
 ```protobuf
+// ./proto/greeter.proto
 syntax = "proto3";
 
 option java_multiple_files = true;
-option java_package = "io.grpc.examples.helloworld";
-option java_outer_classname = "HelloWorldProto";
 
-package helloworld;
+package org.apache.dubbo.sample.tri;
 
-// The greeting service definition.
-service Greeter {
-  // Sends a greeting
-  rpc SayHello (HelloRequest) returns (HelloReply) {}
-}
 
 // The request message containing the user's name.
-message HelloRequest {
+message GreeterRequest {
   string name = 1;
 }
 
 // The response message containing the greetings
-message HelloReply {
+message GreeterReply {
   string message = 1;
 }
+
+service Greeter{
+
+  // unary
+  rpc greet(GreeterRequest) returns (GreeterReply);
+
+  // clientStream
+  rpc greetClientStream(stream GreeterRequest) returns (GreeterReply);
+
+  // serverStream
+  rpc greetServerStream(GreeterRequest) returns (stream GreeterReply);
+
+  // bi streaming
+  rpc greetStream(stream GreeterRequest) returns (stream GreeterReply);
+
+}
 ```
 
-## 3 添加 Dubbo 依赖到项目
-```rust
+## 3 添加 Dubbo-rust 及相关依赖到项目
+```toml
+# ./Cargo.toml
+[package]
+name = "example-greeter"
+version = "0.1.0"
+edition = "2021"
+
+[[bin]]
+name = "greeter-server"
+path = "src/greeter/server.rs"
+
+[[bin]]
+name = "greeter-client"
+path = "src/greeter/client.rs"
+
 [dependencies]
-dubbo = <dubbo-version>
+http = "0.2"
+http-body = "0.4.4"
+futures-util = {version = "0.3", default-features = false}
+tokio = { version = "1.0", features = [ "rt-multi-thread", "time", "fs", 
"macros", "net", "signal"] }
+prost-derive = {version = "0.10", optional = true}
+prost = "0.10.4"
+async-trait = "0.1.56"
+tokio-stream = "0.1"
+
+dubbo = "0.1.0"
+dubbo-config = "0.1.0"
 
 [build-dependencies]
-dubbo-build = <dubbo-version>
+dubbo-build = "0.1.0"
 ```
 
 ## 4 配置 dubbo-build 编译 IDL
+
 在项目根目录创建 (not /src),创建 `build.rs` 文件并添加以下内容:
 
 ```rust
-fn main() -> Result<(), Box<dyn std::error::Error>> {
-    tonic_build::compile_protos("proto/helloworld.proto")?;
-    Ok(())
+// ./build.rs
+fn main() {
+    dubbo_build::prost::configure()
+        .compile(&["proto/greeter.proto"], &["proto/"])
+        .unwrap();
 }
 ```
-这样配置之后,编译项目就可以生成 Dubbo Stub 相关代码,如下:
-
-```rust
-// 部分生成的代码
-```
+这样配置之后,编译项目就可以生成 Dubbo Stub 
相关代码,路径一般在`./target/debug/build/example-greeter-<id>/out/org.apache.dubbo.sample.tri.rs`。
 
 ## 5 编写 Dubbo 业务代码
 
 ### 5.1 编写 Dubbo Server
+
 ```rust
-// 用 dubbo-build 生成的基础类实现业务逻辑,注册服务并启动 server
+// ./src/greeter/server.rs
+pub mod protos {
+    include!(concat!(env!("OUT_DIR"), "/org.apache.dubbo.sample.tri.rs"));
+}
+
+use futures_util::StreamExt;
+use protos::{
+    greeter_server::{register_server, Greeter},
+    GreeterReply, GreeterRequest,
+};
+
+use std::{io::ErrorKind, pin::Pin};
+
+use async_trait::async_trait;
+use futures_util::Stream;
+use tokio::sync::mpsc;
+use tokio_stream::wrappers::ReceiverStream;
+
+use dubbo_config::RootConfig;
+use dubbo::{codegen::*, Dubbo};
+
+type ResponseStream =
+    Pin<Box<dyn Stream<Item = Result<GreeterReply, dubbo::status::Status>> + 
Send>>;
+
+#[tokio::main]
+async fn main() {
+    register_server(GreeterServerImpl {
+        name: "greeter".to_string(),
+    });
+
+    // Dubbo::new().start().await;
+    Dubbo::new()
+        .with_config({
+            let r = RootConfig::new();
+            match r.load() {
+                Ok(config) => config,
+                Err(_err) => panic!("err: {:?}", _err), // response was droped
+            }
+        })
+        .start()
+        .await;
+}
+
+#[allow(dead_code)]
+#[derive(Default, Clone)]
+struct GreeterServerImpl {
+    name: String,
+}
+
+// #[async_trait]
+#[async_trait]
+impl Greeter for GreeterServerImpl {
+    async fn greet(
+        &self,
+        request: Request<GreeterRequest>,
+    ) -> Result<Response<GreeterReply>, dubbo::status::Status> {
+        println!("GreeterServer::greet {:?}", request.metadata);
+
+        Ok(Response::new(GreeterReply {
+            message: "hello, dubbo-rust".to_string(),
+        }))
+    }
+
+    async fn greet_client_stream(
+        &self,
+        request: Request<Decoding<GreeterRequest>>,
+    ) -> Result<Response<GreeterReply>, dubbo::status::Status> {
+        let mut s = request.into_inner();
+        loop {
+            let result = s.next().await;
+            match result {
+                Some(Ok(val)) => println!("result: {:?}", val),
+                Some(Err(val)) => println!("err: {:?}", val),
+                None => break,
+            }
+        }
+        Ok(Response::new(GreeterReply {
+            message: "hello client streaming".to_string(),
+        }))
+    }
+
+    type greetServerStreamStream = ResponseStream;
+    async fn greet_server_stream(
+        &self,
+        request: Request<GreeterRequest>,
+    ) -> Result<Response<Self::greetServerStreamStream>, 
dubbo::status::Status> {
+        println!("greet_server_stream: {:?}", request.into_inner());
+
+        let data = vec![
+            Result::<_, dubbo::status::Status>::Ok(GreeterReply {
+                message: "msg1 from server".to_string(),
+            }),
+            Result::<_, dubbo::status::Status>::Ok(GreeterReply {
+                message: "msg2 from server".to_string(),
+            }),
+            Result::<_, dubbo::status::Status>::Ok(GreeterReply {
+                message: "msg3 from server".to_string(),
+            }),
+        ];
+        let resp = futures_util::stream::iter(data);
+
+        Ok(Response::new(Box::pin(resp)))
+    }
+
+    type greetStreamStream = ResponseStream;
+    async fn greet_stream(
+        &self,
+        request: Request<Decoding<GreeterRequest>>,
+    ) -> Result<Response<Self::greetStreamStream>, dubbo::status::Status> {
+        println!(
+            "GreeterServer::greet_stream, grpc header: {:?}",
+            request.metadata
+        );
+
+        let mut in_stream = request.into_inner();
+        let (tx, rx) = mpsc::channel(128);
+
+        // this spawn here is required if you want to handle connection error.
+        // If we just map `in_stream` and write it back as `out_stream` the 
`out_stream`
+        // will be drooped when connection error occurs and error will never 
be propagated
+        // to mapped version of `in_stream`.
+        tokio::spawn(async move {
+            while let Some(result) = in_stream.next().await {
+                match result {
+                    Ok(v) => {
+                        // if v.name.starts_with("msg2") {
+                        //     
tx.send(Err(dubbo::status::Status::internal(format!("err: args is invalid, 
{:?}", v.name))
+                        //     )).await.expect("working rx");
+                        //     continue;
+                        // }
+                        tx.send(Ok(GreeterReply {
+                            message: format!("server reply: {:?}", v.name),
+                        }))
+                        .await
+                        .expect("working rx")
+                    }
+                    Err(err) => {
+                        if let Some(io_err) = match_for_io_error(&err) {
+                            if io_err.kind() == ErrorKind::BrokenPipe {
+                                // here you can handle special case when client
+                                // disconnected in unexpected way
+                                eprintln!("\tclient disconnected: broken 
pipe");
+                                break;
+                            }
+                        }
+
+                        match tx.send(Err(err)).await {
+                            Ok(_) => (),
+                            Err(_err) => break, // response was droped
+                        }
+                    }
+                }
+            }
+            println!("\tstream ended");
+        });
+
+        // echo just write the same data that was received
+        let out_stream = ReceiverStream::new(rx);
+
+        Ok(Response::new(
+            Box::pin(out_stream) as Self::greetStreamStream
+        ))
+    }
+}
+
+fn match_for_io_error(err_status: &dubbo::status::Status) -> 
Option<&std::io::Error> {
+    let mut err: &(dyn std::error::Error + 'static) = err_status;
+
+    loop {
+        if let Some(io_err) = err.downcast_ref::<std::io::Error>() {
+            return Some(io_err);
+        }
+
+        err = match err.source() {
+            Some(err) => err,
+            None => return None,
+        };
+    }
+}
 ```
 
-### 5.2 编写 Dubbo Client
+### 5.2 配置dubbo.yaml
+
+dubbo.yaml指示server端的配置,包括暴露的服务列表、协议配置、监听配置等。
+
+```yaml
+# ./dubbo.yaml
+name: dubbo
+service:
+  org.apache.dubbo.sample.tri.Greeter:
+    version: 1.0.0
+    group: test
+    protocol: triple
+    registry: ''
+    serializer: json
+    protocol_configs:
+      triple:
+        ip: 0.0.0.0
+        port: '8888'
+        name: triple
+protocols:
+  triple:
+    ip: 0.0.0.0
+    port: '8888'
+    name: triple
+```
+
+### 5.3 编写 Dubbo Client
+
 ```rust
-// 用 dubbo-build 生成的stub,创建连接channel,调用服务
+// ./src/greeter/client.rs
+pub mod protos {
+    include!(concat!(env!("OUT_DIR"), "/org.apache.dubbo.sample.tri.rs"));
+}
+
+use dubbo::codegen::*;
+use futures_util::StreamExt;
+use protos::{greeter_client::GreeterClient, GreeterRequest};
+
+#[tokio::main]
+async fn main() {
+    let mut cli = 
GreeterClient::new().with_uri("http://127.0.0.1:8888".to_string());
+
+    println!("# unary call");
+    let resp = cli
+        .greet(Request::new(GreeterRequest {
+            name: "message from client".to_string(),
+        }))
+        .await;
+    let resp = match resp {
+        Ok(resp) => resp,
+        Err(err) => return println!("{:?}", err),
+    };
+    let (_parts, body) = resp.into_parts();
+    println!("Response: {:?}", body);
+
+    println!("# client stream");
+    let data = vec![
+        GreeterRequest {
+            name: "msg1 from client streaming".to_string(),
+        },
+        GreeterRequest {
+            name: "msg2 from client streaming".to_string(),
+        },
+        GreeterRequest {
+            name: "msg3 from client streaming".to_string(),
+        },
+    ];
+    let req = futures_util::stream::iter(data);
+    let resp = cli.greet_client_stream(req).await;
+    let client_streaming_resp = match resp {
+        Ok(resp) => resp,
+        Err(err) => return println!("{:?}", err),
+    };
+    let (_parts, resp_body) = client_streaming_resp.into_parts();
+    println!("client streaming, Response: {:?}", resp_body);
+
+    println!("# bi stream");
+    let data = vec![
+        GreeterRequest {
+            name: "msg1 from client".to_string(),
+        },
+        GreeterRequest {
+            name: "msg2 from client".to_string(),
+        },
+        GreeterRequest {
+            name: "msg3 from client".to_string(),
+        },
+    ];
+    let req = futures_util::stream::iter(data);
+
+    let bidi_resp = cli.greet_stream(req).await.unwrap();
+
+    let (parts, mut body) = bidi_resp.into_parts();
+    println!("parts: {:?}", parts);
+    while let Some(item) = body.next().await {
+        match item {
+            Ok(v) => {
+                println!("reply: {:?}", v);
+            }
+            Err(err) => {
+                println!("err: {:?}", err);
+            }
+        }
+    }
+    let trailer = body.trailer().await.unwrap();
+    println!("trailer: {:?}", trailer);
+
+    println!("# server stream");
+    let resp = cli
+        .greet_server_stream(Request::new(GreeterRequest {
+            name: "server streaming req".to_string(),
+        }))
+        .await
+        .unwrap();
+
+    let (parts, mut body) = resp.into_parts();
+    println!("parts: {:?}", parts);
+    while let Some(item) = body.next().await {
+        match item {
+            Ok(v) => {
+                println!("reply: {:?}", v);
+            }
+            Err(err) => {
+                println!("err: {:?}", err);
+            }
+        }
+    }
+    let trailer = body.trailer().await.unwrap();
+    println!("trailer: {:?}", trailer);
+}
 ```
 
 ## 6 运行并总结
+
+1. 编译
+
+执行`cargo build`来编译server和client。
+
+2. 运行server
+
+执行`./target/debug/greeter-server`来运行server,如上文dubbo.yaml所配置,server会监听8888端口,并以triple协议提供RPC服务:
+
+```sh
+$ ./target/debug/greeter-server
+2022-09-28T23:33:28.104577Z  INFO dubbo::framework: url: Some(Url { uri: 
"triple://0.0.0.0:8888/org.apache.dubbo.sample.tri.Greeter", protocol: 
"triple", location: "0.0.0.0:8888", ip: "0.0.0.0", port: "8888", service_key: 
["org.apache.dubbo.sample.tri.Greeter"], params: {} })
+```
+
+3. 运行client,验证调用是否成功
+
+执行`./target/debug/greeter-client`来运行client,调用`triple://127.0.0.1:8888/org.apache.dubbo.sample.tri.Greeter`下的各种方法:
+
+
+```sh
+$ ./target/debug/greeter-client
+# unary call
+Response: GreeterReply { message: "hello, dubbo-rust" }
+# client stream
+client streaming, Response: GreeterReply { message: "hello client streaming" }
+# bi stream
+parts: Metadata { inner: {"content-type": "application/grpc", "date": "Wed, 28 
Sep 2022 23:34:20 GMT"} }
+reply: GreeterReply { message: "server reply: \"msg1 from client\"" }
+reply: GreeterReply { message: "server reply: \"msg2 from client\"" }
+reply: GreeterReply { message: "server reply: \"msg3 from client\"" }
+trailer: Some(Metadata { inner: {"content-type": "application/grpc", 
"grpc-status": "0", "grpc-message": "poll trailer successfully.", 
"grpc-accept-encoding": "gzip,identity"} })
+# server stream
+parts: Metadata { inner: {"content-type": "application/grpc", "date": "Wed, 28 
Sep 2022 23:34:20 GMT"} }
+reply: GreeterReply { message: "msg1 from server" }
+reply: GreeterReply { message: "msg2 from server" }
+reply: GreeterReply { message: "msg3 from server" }
+trailer: Some(Metadata { inner: {"content-type": "application/grpc", 
"grpc-status": "0", "grpc-message": "poll trailer successfully.", 
"grpc-accept-encoding": "gzip,identity"} })
+```
diff --git a/content/zh/overview/mannual/Rust.md 
b/content/zh/overview/mannual/Rust.md
new file mode 100644
index 00000000000..b722e92f318
--- /dev/null
+++ b/content/zh/overview/mannual/Rust.md
@@ -0,0 +1,13 @@
+---
+type: docs
+title: "Rust SDK"
+linkTitle: "Rust"
+description: ""
+weight: 3
+manualLinkRelref: ../../docs3-v2/rust-sdk/
+manualLinkTarget: _blank
+_build: { render: link }
+---
+
+
+
diff --git a/content/zh/overview/mannual/_index.md 
b/content/zh/overview/mannual/_index.md
index 5c2760651ca..c461b563de4 100755
--- a/content/zh/overview/mannual/_index.md
+++ b/content/zh/overview/mannual/_index.md
@@ -8,33 +8,43 @@ no_list: true
 ---
 
 
-{{< blocks/section color="white" height="auto" >}}
+{{< blocks/section color="white" height="auto">}}
 <div class="td-content list-page">
-    <div class="lead"></div><header class="article-meta">
-    </header><div class="row">
-    <div class="col-sm col-md-6 mb-4 mb-md-0">
-        <div class="h-100 card shadow" href="#">
-            <div class="card-body">
-                <h4 class="card-title">
-                    <a target="_blank" href='{{< relref 
"../../docs3-v2/java-sdk" >}}'>Java SDK</a>
-                </h4>
-                <p>Java SDK</p>
+    <div class="lead"></div>
+    <header class="article-meta"></header>
+    <div class="row">
+        <div class="col-sm col-md-6 mb-4 mb-md-0">
+            <div class="h-100 card shadow" href="#">
+                <div class="card-body">
+                    <h4 class="card-title">
+                        <a target="_blank" href='{{< relref 
"../../docs3-v2/java-sdk" >}}'>Java SDK</a>
+                    </h4>
+                    <p>Java SDK</p>
+                </div>
             </div>
         </div>
-    </div>
-    <div class="col-sm col-md-6 mb-4 mb-md-0">
-        <div class="h-100 card shadow">
-            <div class="card-body">
-                <h4 class="card-title">
-                    <a target="_blank" href='{{< relref 
"../../docs3-v2/golang-sdk" >}}'>Golang SDK</a>
-                </h4>
-                <p>Golang SDK</p>
+        <div class="col-sm col-md-6 mb-4 mb-md-0">
+            <div class="h-100 card shadow">
+                <div class="card-body">
+                    <h4 class="card-title">
+                        <a target="_blank" href='{{< relref 
"../../docs3-v2/golang-sdk" >}}'>Golang SDK</a>
+                    </h4>
+                    <p>Golang SDK</p>
+                </div>
+            </div>
+        </div>
+        <div class="col-sm col-md-6 mb-4 mb-md-0">
+            <div class="h-100 card shadow">
+                <div class="card-body">
+                    <h4 class="card-title">
+                            <a target="_blank" href='{{< relref 
"../../docs3-v2/rust-sdk" >}}'>Rust SDK</a>
+                        </h4>
+                        <p>Rust SDK</p>
+                </div>
             </div>
         </div>
     </div>
-
-</div>
-<hr>
+    <hr>
 </div>
 
 {{< /blocks/section >}}

Reply via email to