Skip to content

Commit 5016f61

Browse files
authored
Invoke examples (#85)
* Update dependencies Signed-off-by: Hauke Jung <[email protected]> * Add grpc invoke examples Signed-off-by: Hauke Jung <[email protected]> * Fix fmt errors Signed-off-by: Hauke Jung <[email protected]> * Install protoc on github workflow Signed-off-by: Hauke Jung <[email protected]> --------- Signed-off-by: Hauke Jung <[email protected]>
1 parent 4cf17de commit 5016f61

File tree

12 files changed

+335
-7
lines changed

12 files changed

+335
-7
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ jobs:
3434
runs-on: ubuntu-latest
3535

3636
steps:
37+
- name: Install Protoc
38+
uses: arduino/setup-protoc@v1
3739
- uses: actions/checkout@v2
3840
- name: Build
3941
run: cargo build

Cargo.toml

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "dapr"
33
version = "0.10.0"
44
authors = ["dapr.io"]
5-
edition = "2018"
5+
edition = "2021"
66
license-file = "LICENSE"
77
repository = "https://github.com/dapr/rust-sdk"
88
description = "Rust SDK for dapr"
@@ -11,14 +11,14 @@ keywords = ["microservices", "dapr"]
1111

1212

1313
[dependencies]
14-
tonic = "0.5"
15-
prost = "0.8"
14+
tonic = "0.8"
15+
prost = "0.11"
1616
bytes = "1"
17-
prost-types = "0.8"
17+
prost-types = "0.11"
1818
async-trait = "0.1"
1919

2020
[build-dependencies]
21-
tonic-build = "0.5"
21+
tonic-build = "0.8"
2222

2323
[dev-dependencies]
2424
tokio = { version = "1", features = ["full"] }
@@ -34,3 +34,19 @@ path = "examples/pubsub/publisher.rs"
3434
[[example]]
3535
name = "subscriber"
3636
path = "examples/pubsub/subscriber.rs"
37+
38+
[[example]]
39+
name = "invoke-grpc-client"
40+
path = "examples/invoke/grpc/client.rs"
41+
42+
[[example]]
43+
name = "invoke-grpc-server"
44+
path = "examples/invoke/grpc/server.rs"
45+
46+
[[example]]
47+
name = "invoke-grpc-proxying-client"
48+
path = "examples/invoke/grpc-proxying/client.rs"
49+
50+
[[example]]
51+
name = "invoke-grpc-proxying-server"
52+
path = "examples/invoke/grpc-proxying/server.rs"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Dapr is a portable, event-driven, serverless runtime for building distributed ap
2929

3030
```toml
3131
[dependencies]
32-
dapr = "0.5.0"
32+
dapr = "0.10.0"
3333
```
3434

3535
A client can be created as follows:

build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ fn main() -> Result<(), std::io::Error> {
77
"dapr/proto/common/v1/common.proto",
88
"dapr/proto/runtime/v1/dapr.proto",
99
"dapr/proto/runtime/v1/appcallback.proto",
10+
"examples/invoke/proto/helloworld.proto",
1011
],
1112
&["."],
1213
)?;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
Before you run the example make sure local redis state store is running by executing:
2+
```
3+
docker ps
4+
```
5+
6+
1. To run the example we need to first build the examples using the following command:
7+
8+
```
9+
cargo build --examples
10+
```
11+
12+
2. Run the example with dapr using the following command:
13+
14+
```
15+
dapr run --app-id=invoke-grpc-server --app-protocol grpc --app-port 50052 -- cargo run --example invoke-grpc-proxying-server
16+
dapr run --app-id=invoke-grpc-client -- cargo run --example invoke-grpc-proxying-client
17+
```
18+
19+
If everything went well you should see the following output along with dapr logs:
20+
```
21+
Response: HelloReply {
22+
message: "Hello Test!",
23+
}
24+
```
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use hello_world::{greeter_client::GreeterClient, HelloRequest};
2+
3+
use tonic::metadata::MetadataValue;
4+
5+
pub mod hello_world {
6+
tonic::include_proto!("helloworld"); // The string specified here must match the proto package name
7+
}
8+
9+
#[tokio::main]
10+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
11+
// Get the Dapr port for gRPC connection
12+
let port: u16 = std::env::var("DAPR_GRPC_PORT").unwrap().parse().unwrap();
13+
let address = format!("https://127.0.0.1:{}", port);
14+
15+
let mut client = GreeterClient::connect(address).await?;
16+
17+
let request = HelloRequest {
18+
name: "Test".to_string(),
19+
};
20+
let mut request = tonic::Request::new(request);
21+
request.metadata_mut().append(
22+
"dapr-app-id",
23+
MetadataValue::from_static("invoke-grpc-server"),
24+
);
25+
26+
let response = client.say_hello(request).await.unwrap();
27+
let hello_reply = response.into_inner();
28+
29+
println!("Response: {:#?}", hello_reply);
30+
31+
Ok(())
32+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use crate::hello_world::greeter_server::{Greeter, GreeterServer};
2+
use crate::hello_world::{HelloReply, HelloRequest};
3+
use tonic::{transport::Server, Request, Response, Status};
4+
5+
pub mod hello_world {
6+
tonic::include_proto!("helloworld"); // The string specified here must match the proto package name
7+
}
8+
9+
#[derive(Debug, Default)]
10+
pub struct GreeterService {}
11+
12+
#[tonic::async_trait]
13+
impl Greeter for GreeterService {
14+
async fn say_hello(
15+
&self,
16+
request: Request<HelloRequest>,
17+
) -> Result<Response<HelloReply>, Status> {
18+
let req = request.into_inner();
19+
20+
let name = req.name;
21+
22+
let response = HelloReply {
23+
message: format!("Hello {name}!"),
24+
};
25+
26+
Ok(Response::new(response))
27+
}
28+
}
29+
30+
#[tokio::main]
31+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
32+
let server_address = "[::]:50052".parse().unwrap();
33+
34+
let greeter_service = GreeterService::default();
35+
36+
println!("AppCallback server listening on: {}", server_address);
37+
// Create a gRPC server with the callback_service.
38+
Server::builder()
39+
.add_service(GreeterServer::new(greeter_service))
40+
.serve(server_address)
41+
.await?;
42+
43+
Ok(())
44+
}

examples/invoke/grpc/README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
Before you run the example make sure local redis state store is running by executing:
2+
```
3+
docker ps
4+
```
5+
6+
1. To run the example we need to first build the examples using the following command:
7+
8+
```
9+
cargo build --examples
10+
```
11+
12+
2. Run the example with dapr using the following command:
13+
14+
```
15+
dapr run --app-id=invoke-grpc-server --app-protocol grpc --app-port 50052 -- cargo run --example invoke-grpc-server
16+
dapr run --app-id=invoke-grpc-client -- cargo run --example invoke-grpc-client
17+
```
18+
19+
If everything went well you should see the following output along with dapr logs:
20+
```
21+
Message: "Hello World!"
22+
Response: InvokeResponse {
23+
data: Some(
24+
Any {
25+
type_url: "",
26+
value: [
27+
10,
28+
12,
29+
72,
30+
101,
31+
108,
32+
108,
33+
111,
34+
32,
35+
87,
36+
111,
37+
114,
38+
108,
39+
100,
40+
33,
41+
],
42+
},
43+
),
44+
content_type: "application/json",
45+
}
46+
```
47+

examples/invoke/grpc/client.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use hello_world::{HelloReply, HelloRequest};
2+
use prost::Message;
3+
4+
pub mod hello_world {
5+
tonic::include_proto!("helloworld"); // The string specified here must match the proto package name
6+
}
7+
8+
type DaprClient = dapr::Client<dapr::client::TonicClient>;
9+
10+
#[tokio::main]
11+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
12+
// Get the Dapr port for gRPC connection
13+
let port: u16 = std::env::var("DAPR_GRPC_PORT").unwrap().parse().unwrap();
14+
let address = format!("https://127.0.0.1:{}", port);
15+
16+
let mut client = DaprClient::connect(address).await?;
17+
18+
let request = HelloRequest {
19+
name: "Test".to_string(),
20+
};
21+
let data = request.encode_to_vec();
22+
let data = prost_types::Any {
23+
type_url: "".to_string(),
24+
value: data,
25+
};
26+
27+
let response = client
28+
.invoke_service("invoke-grpc-server", "say_hello", Some(data))
29+
.await
30+
.unwrap();
31+
32+
if let Some(any) = &response.data {
33+
let data = &any.value;
34+
let resp = HelloReply::decode(&data[..]).unwrap();
35+
println!("Message: {:#?}", &resp.message);
36+
};
37+
38+
println!("Response: {:#?}", response);
39+
40+
Ok(())
41+
}

examples/invoke/grpc/server.rs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
use dapr::{
2+
appcallback::*,
3+
dapr::dapr::proto::runtime::v1::app_callback_server::{AppCallback, AppCallbackServer},
4+
};
5+
use prost::Message;
6+
use tonic::{transport::Server, Request, Response, Status};
7+
8+
use hello_world::{HelloReply, HelloRequest};
9+
10+
pub mod hello_world {
11+
tonic::include_proto!("helloworld"); // The string specified here must match the proto package name
12+
}
13+
14+
pub struct AppCallbackService {}
15+
16+
#[tonic::async_trait]
17+
impl AppCallback for AppCallbackService {
18+
/// Invokes service method with InvokeRequest.
19+
async fn on_invoke(
20+
&self,
21+
request: Request<InvokeRequest>,
22+
) -> Result<Response<InvokeResponse>, Status> {
23+
let r = request.into_inner();
24+
25+
let method = &r.method;
26+
println!("Method: {method}");
27+
let data = &r.data;
28+
29+
if let Some(any) = data {
30+
let data = &any.value;
31+
let resp = HelloRequest::decode(&data[..]).unwrap();
32+
println!("Name: {:#?}", &resp.name);
33+
34+
let response = HelloReply {
35+
message: "Hello World!".to_string(),
36+
};
37+
let data = response.encode_to_vec();
38+
39+
let data = prost_types::Any {
40+
type_url: "".to_string(),
41+
value: data,
42+
};
43+
44+
let invoke_response = InvokeResponse {
45+
content_type: "application/json".to_string(),
46+
data: Some(data),
47+
};
48+
49+
return Ok(Response::new(invoke_response));
50+
};
51+
52+
Ok(Response::new(InvokeResponse::default()))
53+
}
54+
55+
/// Lists all topics subscribed by this app.
56+
///
57+
/// NOTE: Dapr runtime will call this method to get
58+
/// the list of topics the app wants to subscribe to.
59+
/// In this example, the app is subscribing to topic `A`.
60+
async fn list_topic_subscriptions(
61+
&self,
62+
_request: Request<()>,
63+
) -> Result<Response<ListTopicSubscriptionsResponse>, Status> {
64+
let list_subscriptions = ListTopicSubscriptionsResponse::default();
65+
Ok(Response::new(list_subscriptions))
66+
}
67+
68+
/// Subscribes events from Pubsub.
69+
async fn on_topic_event(
70+
&self,
71+
_request: Request<TopicEventRequest>,
72+
) -> Result<Response<TopicEventResponse>, Status> {
73+
Ok(Response::new(TopicEventResponse::default()))
74+
}
75+
76+
/// Lists all input bindings subscribed by this app.
77+
async fn list_input_bindings(
78+
&self,
79+
_request: Request<()>,
80+
) -> Result<Response<ListInputBindingsResponse>, Status> {
81+
Ok(Response::new(ListInputBindingsResponse::default()))
82+
}
83+
84+
/// Listens events from the input bindings.
85+
async fn on_binding_event(
86+
&self,
87+
_request: Request<BindingEventRequest>,
88+
) -> Result<Response<BindingEventResponse>, Status> {
89+
Ok(Response::new(BindingEventResponse::default()))
90+
}
91+
}
92+
93+
#[tokio::main]
94+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
95+
let server_address = "[::]:50052".parse().unwrap();
96+
97+
let callback_service = AppCallbackService {};
98+
99+
println!("AppCallback server listening on: {}", server_address);
100+
// Create a gRPC server with the callback_service.
101+
Server::builder()
102+
.add_service(AppCallbackServer::new(callback_service))
103+
.serve(server_address)
104+
.await?;
105+
106+
Ok(())
107+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
syntax = "proto3";
2+
package helloworld;
3+
4+
service Greeter {
5+
rpc SayHello (HelloRequest) returns (HelloReply);
6+
}
7+
8+
message HelloRequest {
9+
string name = 1;
10+
}
11+
12+
message HelloReply {
13+
string message = 1;
14+
}

rustfmt.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
edition = "2018"
1+
edition = "2021"

0 commit comments

Comments
 (0)