Skip to content

Commit a6b9941

Browse files
authored
Add Rust streaming codelab (#50)
1 parent 8d2003a commit a6b9941

25 files changed

+13160
-0
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Generate Code from Proto Files
2+
3+
This is a tutorial for generating code from Proto files using gRPC-Rust. This tutorial will utilize the RouteGuide example.
4+
5+
### Prerequisites
6+
7+
* [**Tonic**](https://github.com/hyperium/tonic.git), the open source repository that gRPC-Rust is build off on
8+
```sh
9+
$ git clone https://github.com/hyperium/tonic.git
10+
```
11+
* [**Rust**](https://www.rust-lang.org/).
12+
* Follow installation instructions [here](https://www.rust-lang.org/tools/install).
13+
* [**Bazel 8.3.1**](https://bazel.build/).
14+
* Follow installation instructions [here](https://github.com/bazelbuild/bazel/releases).
15+
* [**Protocol buffer**](https://developers.google.com/protocol-buffers) **compiler**, `protoc`, [version 3](https://protobuf.dev/programming-guides/proto3).
16+
* For installation instructions, see [Protocol Buffer Compiler Installation](https://grpc.io/docs/protoc-installation/).
17+
* NOTE: Must need a version of Protoc 3.31.1 or higher.
18+
* **Rust plugins** for the protocol compiler:
19+
```sh
20+
$ cd tonic/protoc-gen-rust-grpc
21+
$ bazel build //src:protoc-gen-rust-grpc
22+
$ PLUGIN_PATH="$(pwd)/bazel-bin/src/protoc-gen-rust-grpc"
23+
```
24+
25+
* Update your PATH so that the protoc compiler can find the plugins:
26+
27+
```sh
28+
export PATH="$(pwd)/bazel-bin/src/:$PATH"
29+
```
30+
31+
## Generating client and server code
32+
33+
Next we need to generate the gRPC client and server interfaces from our `.proto`
34+
service definition.
35+
36+
### Dependencies
37+
Edit `Cargo.toml` and add all the dependencies we'll need for this example:
38+
39+
```toml
40+
[package]
41+
edition = "2021"
42+
license = "MIT"
43+
name = "getting-started"
44+
45+
[[bin]]
46+
name = "routeguide-server"
47+
path = "src/server/server.rs"
48+
49+
[[bin]]
50+
name = "routeguide-client"
51+
path = "src/client/client.rs"
52+
53+
[features]
54+
routeguide = ["dep:async-stream", "dep:tokio-stream", "dep:rand", "dep:serde", "dep:serde_json"]
55+
full = ["routeguide"]
56+
default = ["full"]
57+
58+
[dependencies]
59+
# Common dependencies
60+
tokio = { version = "1.0", features = ["rt-multi-thread", "macros"] }
61+
prost = "0.14"
62+
tonic = { git = "https://github.com/hyperium/tonic", branch="master"}
63+
tonic-protobuf = {git = "https://github.com/hyperium/tonic", branch = "master", package = "tonic-protobuf" }
64+
grpc = {git = "https://github.com/hyperium/tonic", branch = "master", package = "grpc"}
65+
tonic-prost = {git = "https://github.com/hyperium/tonic", branch = "master", package = "tonic-prost" }
66+
# Optional dependencies
67+
async-stream = { version = "0.3", optional = true }
68+
tokio-stream = { version = "0.1", optional = true }
69+
tokio-util = { version = "0.7.8", optional = true }
70+
tower = { version = "0.5", optional = true }
71+
rand = { version = "0.9", optional = true }
72+
serde = { version = "1.0", features = ["derive"], optional = true }
73+
serde_json = { version = "1.0", optional = true }
74+
prost-types = { version = "0.14", optional = true }
75+
http = { version = "1", optional = true }
76+
hyper = { version = "1", optional = true }
77+
hyper-util = { version = "0.1.4", optional = true }
78+
tokio-rustls = { version = "0.26.1", optional = true, features = ["ring", "tls12"], default-features = false }
79+
hyper-rustls = { version = "0.27.0", features = ["http2", "ring", "tls12"], optional = true, default-features = false }
80+
tower-http = { version = "0.6", optional = true }
81+
protobuf = { version = "4.31.1-release"}
82+
83+
[build-dependencies]
84+
tonic-protobuf-build = {git = "https://github.com/hyperium/tonic.git", branch = "master", package = "tonic-protobuf-build" }
85+
```
86+
87+
### Compiling and Building Proto
88+
Create a `build.rs` file at the root of your crate. A build.rs script is a Rust program that Cargo executes before compiling your main project. Its purpose is to perform tasks like generating source code, linking to non-Rust libraries, or setting environment variables that influence the build process.
89+
90+
In this case, we will be putting the command to compile and build the `.proto` file in build.rs. We will use gRPC's tonic_protobuf_build crate to generate code from the `.proto` file.
91+
```rust
92+
fn main() {
93+
tonic_protobuf_build::CodeGen::new()
94+
.include("proto")
95+
.inputs(["routeguide.proto"])
96+
.output_dir("generated")
97+
.compile()
98+
.unwrap();
99+
}
100+
```
101+
Now, run
102+
```shell
103+
$ cargo build
104+
```
105+
106+
## Bringing Generated Code into Scope
107+
108+
The generated code is placed inside our target directory, in a location defined by the `OUT_DIR`
109+
environment variable that is set by cargo. For our example, this means you can find the generated
110+
code in a path similar to `target/debug/build/routeguide/out/routeguide.rs`.
111+
112+
We can use gRPC's `include_proto` macro to bring the generated code into scope:
113+
114+
```rust
115+
pub mod routeguide {
116+
grpc::include_proto!("routeguide");
117+
}
118+
```
119+
120+
**Note**: The token passed to the `include_proto` macro (in our case "routeguide") is the name of
121+
the package declared in our `.proto` file, not a filename, e.g "routeguide.rs".
122+
123+
With this in place, we can stub out our service implementation:
124+
125+
126+
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
[package]
2+
authors = ["Lucio Franco <[email protected]>"]
3+
edition = "2021"
4+
license = "MIT"
5+
name = "examples"
6+
7+
[[bin]]
8+
name = "routeguide-server"
9+
path = "src/server/server.rs"
10+
required-features = ["routeguide"]
11+
12+
[[bin]]
13+
name = "routeguide-client"
14+
path = "src/client/client.rs"
15+
required-features = ["routeguide"]
16+
17+
[features]
18+
gcp = ["dep:prost-types", "tonic/tls-ring"]
19+
routeguide = ["dep:async-stream", "dep:tokio-stream", "dep:rand", "dep:serde", "dep:serde_json"]
20+
reflection = ["dep:tonic-reflection"]
21+
autoreload = ["dep:tokio-stream", "tokio-stream?/net", "dep:listenfd"]
22+
health = ["dep:tonic-health"]
23+
grpc-web = ["dep:tonic-web", "dep:bytes", "dep:http", "dep:hyper", "dep:hyper-util", "dep:tracing-subscriber", "dep:tower", "dep:tower-http", "tower-http?/cors"]
24+
tracing = ["dep:tracing", "dep:tracing-subscriber"]
25+
uds = ["dep:tokio-stream", "tokio-stream?/net", "dep:tower", "dep:hyper", "dep:hyper-util"]
26+
streaming = ["dep:tokio-stream", "dep:h2"]
27+
mock = ["dep:tokio-stream", "dep:tower", "dep:hyper-util"]
28+
tower = ["dep:tower", "dep:http"]
29+
json-codec = ["dep:serde", "dep:serde_json", "dep:bytes"]
30+
compression = ["tonic/gzip"]
31+
tls = ["tonic/tls-ring"]
32+
tls-rustls = ["dep:http", "dep:hyper", "dep:hyper-util", "dep:hyper-rustls", "dep:tower", "tower-http/util", "tower-http/add-extension", "dep:tokio-rustls"]
33+
tls-client-auth = ["tonic/tls-ring"]
34+
types = ["dep:tonic-types"]
35+
h2c = ["dep:hyper", "dep:tower", "dep:http", "dep:hyper-util"]
36+
cancellation = ["dep:tokio-util"]
37+
38+
full = ["gcp", "routeguide", "reflection", "autoreload", "health", "grpc-web", "tracing", "uds", "streaming", "mock", "tower", "json-codec", "compression", "tls", "tls-rustls", "tls-client-auth", "types", "cancellation", "h2c"]
39+
default = ["full"]
40+
41+
[dependencies]
42+
# Common dependencies
43+
tokio = { version = "1.0", features = ["rt-multi-thread", "macros"] }
44+
prost = "0.14"
45+
tonic = { git = "https://github.com/arjan-bal/tonic.git", branch = "grpc-codegen" }
46+
tonic-protobuf = {git = "https://github.com/arjan-bal/tonic.git", branch = "grpc-codegen", package = "tonic-protobuf" }
47+
grpc = {git = "https://github.com/arjan-bal/tonic.git", branch = "grpc-codegen", package = "grpc"}
48+
49+
# Optional dependencies
50+
async-stream = { version = "0.3", optional = true }
51+
tokio-stream = { version = "0.1", optional = true }
52+
tokio-util = { version = "0.7.8", optional = true }
53+
tonic-web = { git = "https://github.com/arjan-bal/tonic.git", branch = "grpc-codegen", package = "tonic-web", optional = true }
54+
tonic-health = { git = "https://github.com/arjan-bal/tonic.git", branch = "grpc-codegen", package = "tonic-health", optional = true }
55+
tonic-reflection = { git = "https://github.com/arjan-bal/tonic.git", branch = "grpc-codegen", package = "tonic-reflection", optional = true }
56+
tonic-types = { git = "https://github.com/arjan-bal/tonic.git", branch = "grpc-codegen", package = "tonic-types", optional = true }
57+
tower = { version = "0.5", optional = true }
58+
rand = { version = "0.9", optional = true }
59+
serde = { version = "1.0", features = ["derive"], optional = true }
60+
serde_json = { version = "1.0", optional = true }
61+
prost-types = { version = "0.14", optional = true }
62+
http = { version = "1", optional = true }
63+
hyper = { version = "1", optional = true }
64+
hyper-util = { version = "0.1.4", optional = true }
65+
tokio-rustls = { version = "0.26.1", optional = true, features = ["ring", "tls12"], default-features = false }
66+
hyper-rustls = { version = "0.27.0", features = ["http2", "ring", "tls12"], optional = true, default-features = false }
67+
tower-http = { version = "0.6", optional = true }
68+
protobuf = { version = "4.31.1-release"}
69+
listenfd = { version = "1.0", optional = true }
70+
bytes = { version = "1", optional = true }
71+
h2 = { version = "0.4", optional = true }
72+
tracing = { version = "0.1.16", optional = true }
73+
tracing-subscriber = { version = "0.3", features = ["tracing-log", "fmt"], optional = true }
74+
75+
[build-dependencies]
76+
protobuf-codegen = { version = "4.31.1-release"}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn main() {
2+
protobuf_codegen::CodeGen::new()
3+
.include("proto")
4+
.inputs(["routeguide.proto"])
5+
.output_dir("generated")
6+
.compile_only()
7+
.unwrap();
8+
}

codelabs/grpc-rust-streaming/completed/generated/crate_mapping.txt

Whitespace-only changes.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#[path = "routeguide.u.pb.rs"]
2+
#[allow(nonstandard_style)]
3+
pub mod internal_do_not_use_routeguide;
4+
#[allow(unused_imports, nonstandard_style)]
5+
pub use internal_do_not_use_routeguide::*;

0 commit comments

Comments
 (0)