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 >}}