From 4e5c6c8f2354301aed984da891ef284d16c936e5 Mon Sep 17 00:00:00 2001 From: Juan Alvarez Date: Thu, 19 Dec 2019 17:23:26 -0600 Subject: [PATCH] chore(example): update guides to 0.1-beta.1 (#198) * update routeguide * update helloworld * depend on tonic beta.1 * Apply suggestions from code review Co-Authored-By: Lucio Franco Co-authored-by: Lucio Franco --- examples/helloworld-tutorial.md | 39 ++++++++--------- examples/routeguide-tutorial.md | 73 +++++++++++++++---------------- examples/src/helloworld/client.rs | 5 ++- examples/src/helloworld/server.rs | 10 ++--- examples/src/routeguide/client.rs | 22 +++++----- examples/src/routeguide/data.rs | 3 +- examples/src/routeguide/server.rs | 27 +++++------- 7 files changed, 86 insertions(+), 93 deletions(-) diff --git a/examples/helloworld-tutorial.md b/examples/helloworld-tutorial.md index 32cd025..2beabf8 100644 --- a/examples/helloworld-tutorial.md +++ b/examples/helloworld-tutorial.md @@ -113,14 +113,13 @@ name = "helloworld-client" path = "src/client.rs" [dependencies] -tonic = "0.1.0-alpha.5" +tonic = "0.1.0-beta.1" bytes = "0.4" prost = "0.5" -prost-derive = "0.5" -tokio = "=0.2.0-alpha.6" +tokio = { version = "0.2", features = ["macros"] } [build-dependencies] -tonic-build = "0.1.0-alpha.5" +tonic-build = "0.1.0-beta.1" ``` We include `tonic-build` as a useful way to incorporate the generation of our client and server gRPC code into the build process of our application. We will setup this build process now: @@ -147,19 +146,18 @@ Now that the build process is written and our dependencies are all setup, we can ```rust 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 } - -use hello_world::{ - server::{Greeter, GreeterServer}, - HelloReply, HelloRequest, -}; ``` Next up, let's implement the Greeter service we previously defined in our `.proto` file. Here's what that might look like: ```rust +#[derive(Debug, Default)] pub struct MyGreeter {} #[tonic::async_trait] @@ -185,7 +183,7 @@ Finally, let's define the Tokio runtime that our server will actually run on. Th #[tokio::main] async fn main() -> Result<(), Box> { let addr = "[::1]:50051".parse()?; - let greeter = MyGreeter {}; + let greeter = MyGreeter::default(); Server::builder() .add_service(GreeterServer::new(greeter)) @@ -201,15 +199,14 @@ Altogether your server should look something like this once you are done: ```rust 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"); } -use hello_world::{ - server::{Greeter, GreeterServer}, - HelloReply, HelloRequest, -}; - +#[derive(Debug, Default)] pub struct MyGreeter {} #[tonic::async_trait] @@ -231,7 +228,7 @@ impl Greeter for MyGreeter { #[tokio::main] async fn main() -> Result<(), Box> { let addr = "[::1]:50051".parse()?; - let greeter = MyGreeter {}; + let greeter = MyGreeter::default(); Server::builder() .add_service(GreeterServer::new(greeter)) @@ -251,11 +248,12 @@ You should now be able to run your HelloWorld gRPC server using the command `car So now we have a running gRPC server, and that's great but how can our application communicate with it? This is where our client would come in. Tonic supports both client and server implementations. Similar to the server, we will start by creating a file `client.rs` in our `/src` directory and importing everything we will need: ```rust +use hello_world::greeter_client::GreeterClient; +use hello_world::HelloRequest; + pub mod hello_world { tonic::include_proto!("helloworld"); } - -use hello_world::{client::GreeterClient, HelloRequest}; ``` The client is much simpler than the server as we don't need to implement any service methods, just make requests. Here is a Tokio runtime which will make our request and print the response to your terminal: @@ -280,12 +278,13 @@ async fn main() -> Result<(), Box> { That's it! Our complete client file should look something like below, if it doesn't please go back and make sure you followed along correctly: ```rust +use hello_world::greeter_client::GreeterClient; +use hello_world::HelloRequest; + pub mod hello_world { tonic::include_proto!("helloworld"); } -use hello_world::{client::GreeterClient, HelloRequest}; - #[tokio::main] async fn main() -> Result<(), Box> { let mut client = GreeterClient::connect("http://[::1]:50051").await?; diff --git a/examples/routeguide-tutorial.md b/examples/routeguide-tutorial.md index 6020e39..a8483fd 100644 --- a/examples/routeguide-tutorial.md +++ b/examples/routeguide-tutorial.md @@ -180,18 +180,20 @@ Edit `Cargo.toml` and add all the dependencies we'll need for this example: ```toml [dependencies] -async-stream = "0.1.2" +tonic = "0.1.0-beta.1" bytes = "0.4" -futures-preview = { version = "0.3.0-alpha.19", default-features = false, features = ["alloc"]} +prost = "0.5" +futures-core = "0.3" +futures-util = "0.3" +tokio = { version = "0.2", features = ["macros", "sync", "stream", "time"] } + +async-stream = "0.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -prost = "0.5" -rand = "0.7.2" -tokio = "0.2.0-alpha.6" -tonic = "0.1.0-alpha.5" +rand = "0.7" [build-dependencies] -tonic-build = "0.1.0-alpha.5" +tonic-build = "0.1.0-beta.1" ``` Create a `build.rs` file at the root of your crate: @@ -210,8 +212,8 @@ $ cargo build That's it. The generated code contains: - Struct definitions for message types `Point`, `Rectangle`, `Feature`, `RouteNote`, `RouteSummary`. -- A service trait we'll need to implement: `server::RouteGuide`. -- A client type we'll use to call the server: `client::RouteGuideClient`. +- A service trait we'll need to implement: `route_guide_server::RouteGuide`. +- A client type we'll use to call the server: `route_guide_client::RouteGuideClient`. If your are curious as to where the generated files are, keep reading. The mystery will be revealed soon! We can now move on to the fun part. @@ -234,16 +236,16 @@ You can find our example `RouteGuide` server in [routeguide-server]: https://github.com/hyperium/tonic/blob/master/examples/src/routeguide/server.rs -### Implementing the server::RouteGuide trait +### Implementing the RouteGuide server trait We can start by defining a struct to represent our service, we can do this on `main.rs` for now: ```rust #[derive(Debug)] -struct RouteGuide; +struct RouteGuideService; ``` -Next, we need to implement the `server::RouteGuide` trait that is generated in our build step. +Next, we need to implement the `route_guide_server::RouteGuide` trait that is generated in our build step. The generated code is placed inside our target directory, in a location defined by the `OUT_DIR` environment variable that is set by cargo. For our example, this means you can find the generated code in a path similar to `target/debug/build/routeguide/out/routeguide.rs`. @@ -257,7 +259,8 @@ pub mod routeguide { tonic::include_proto!("routeguide"); } -use routeguide::{server, Feature, Point, Rectangle, RouteNote, RouteSummary}; +use routeguide::route_guide_server::RouteGuide; +use routeguide::{Feature, Point, Rectangle, RouteNote, RouteSummary}; ``` **Note**: The token passed to the `include_proto` macro (in our case "routeguide") is the name of @@ -266,10 +269,11 @@ the package declared in in our `.proto` file, not a filename, e.g "routeguide.rs With this in place, we can stub out our service implementation: ```rust -use tonic::{Request, Response, Status}; -use tokio::sync::mpsc; use std::pin::Pin; -use futures::Stream; + +use futures_core::Stream; +use tokio::sync::mpsc; +use tonic::{Request, Response, Status}; ``` ```rust @@ -320,7 +324,7 @@ deserialize them from a json file and keep them around as our only piece of shar ```rust #[derive(Debug)] -pub struct RouteGuide { +pub struct RouteGuideService { features: Arc>, } ``` @@ -389,12 +393,7 @@ async fn get_feature(&self, request: Request) -> Result } } - let response = Response::new(Feature { - name: "".to_string(), - location: None, - }); - - Ok(response) + Ok(Response::new(Feature::default())) } ``` @@ -441,7 +440,7 @@ with information about their trip. As you can see, this time the method receives ```rust use std::time::Instant; -use futures::StreamExt; +use futures_util::StreamExt; ``` ```rust @@ -552,12 +551,9 @@ async fn main() -> Result<(), Box> { features: Arc::new(data::load()), }; - let svc = server::RouteGuideServer::new(route_guide); + let svc = RouteGuideServer::new(route_guide); - Server::builder() - .add_service(svc) - .serve(addr) - .await?; + Server::builder().add_service(svc).serve(addr).await?; Ok(()) } @@ -603,11 +599,13 @@ $ touch src/client.rs To call service methods, we first need to create a gRPC *client* to communicate with the server. ```rust -pub mod route_guide { +pub mod routeguide { tonic::include_proto!("routeguide"); } -use route_guide::{client::RouteGuideClient, Point, Rectangle, RouteNote}; +use routeguide::route_guide_client::RouteGuideClient; +use routeguide::{Point, Rectangle, RouteNote}; + #[tokio::main] async fn main() -> Result<(), Box> { @@ -698,7 +696,7 @@ The client-side streaming method `record_route` takes a stream of `Point`s and r ```rust use rand::rngs::ThreadRng; use rand::Rng; -use futures::stream; +use futures_util::stream; ``` ```rust @@ -746,16 +744,16 @@ Finally, let's look at our bidirectional streaming RPC. The `route_chat` method of `RouteNotes` and returns either another stream of `RouteNotes` or an error. ```rust -use std::time::{Duration, Instant}; -use tokio::timer::Interval; +use std::time::Duration; +use tokio::time; ``` ```rust async fn run_route_chat(client: &mut RouteGuideClient) -> Result<(), Box> { - let start = Instant::now(); + let start = time::Instant::now(); let outbound = async_stream::stream! { - let mut interval = Interval::new_interval(Duration::from_secs(1)); + let mut interval = time::interval(Duration::from_secs(1)); while let Some(time) = interval.next().await { let elapsed = time.duration_since(start); @@ -771,8 +769,7 @@ async fn run_route_chat(client: &mut RouteGuideClient) -> Result<(), Bo } }; - let request = Request::new(outbound); - let response = client.route_chat(request).await?; + let response = client.route_chat(Request::new(outbound)).await?; let mut inbound = response.into_inner(); while let Some(note) = inbound.message().await? { diff --git a/examples/src/helloworld/client.rs b/examples/src/helloworld/client.rs index 486e1d8..6e66783 100644 --- a/examples/src/helloworld/client.rs +++ b/examples/src/helloworld/client.rs @@ -1,9 +1,10 @@ +use hello_world::greeter_client::GreeterClient; +use hello_world::HelloRequest; + pub mod hello_world { tonic::include_proto!("helloworld"); } -use hello_world::{greeter_client::GreeterClient, HelloRequest}; - #[tokio::main] async fn main() -> Result<(), Box> { let mut client = GreeterClient::connect("http://[::1]:50051").await?; diff --git a/examples/src/helloworld/server.rs b/examples/src/helloworld/server.rs index a57f4b4..c6398bb 100644 --- a/examples/src/helloworld/server.rs +++ b/examples/src/helloworld/server.rs @@ -1,14 +1,12 @@ 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"); } -use hello_world::{ - greeter_server::{Greeter, GreeterServer}, - HelloReply, HelloRequest, -}; - #[derive(Default)] pub struct MyGreeter {} @@ -32,6 +30,8 @@ async fn main() -> Result<(), Box> { let addr = "[::1]:50051".parse().unwrap(); let greeter = MyGreeter::default(); + println!("GreeterServer listening on {}", addr); + Server::builder() .add_service(GreeterServer::new(greeter)) .serve(addr) diff --git a/examples/src/routeguide/client.rs b/examples/src/routeguide/client.rs index e59f8d6..04b8fd1 100644 --- a/examples/src/routeguide/client.rs +++ b/examples/src/routeguide/client.rs @@ -1,19 +1,20 @@ +use std::error::Error; +use std::time::Duration; + use futures::stream; use rand::rngs::ThreadRng; use rand::Rng; -use route_guide::{Point, Rectangle, RouteNote}; -use std::error::Error; -use std::time::Duration; -use tokio::time::Instant; +use tokio::time; use tonic::transport::Channel; use tonic::Request; -pub mod route_guide { +use routeguide::route_guide_client::RouteGuideClient; +use routeguide::{Point, Rectangle, RouteNote}; + +pub mod routeguide { tonic::include_proto!("routeguide"); } -use route_guide::route_guide_client::RouteGuideClient; - async fn print_features(client: &mut RouteGuideClient) -> Result<(), Box> { let rectangle = Rectangle { lo: Some(Point { @@ -59,10 +60,10 @@ async fn run_record_route(client: &mut RouteGuideClient) -> Result<(), } async fn run_route_chat(client: &mut RouteGuideClient) -> Result<(), Box> { - let start = Instant::now(); + let start = time::Instant::now(); let outbound = async_stream::stream! { - let mut interval = tokio::time::interval(Duration::from_secs(1)); + let mut interval = time::interval(Duration::from_secs(1)); while let time = interval.tick().await { let elapsed = time.duration_since(start); @@ -78,8 +79,7 @@ async fn run_route_chat(client: &mut RouteGuideClient) -> Result<(), Bo } }; - let request = Request::new(outbound); - let response = client.route_chat(request).await?; + let response = client.route_chat(Request::new(outbound)).await?; let mut inbound = response.into_inner(); while let Some(note) = inbound.message().await? { diff --git a/examples/src/routeguide/data.rs b/examples/src/routeguide/data.rs index 41e6ab9..bec3805 100644 --- a/examples/src/routeguide/data.rs +++ b/examples/src/routeguide/data.rs @@ -15,8 +15,7 @@ struct Location { #[allow(dead_code)] pub fn load() -> Vec { - let file = - File::open("tonic-examples/data/route_guide_db.json").expect("failed to open data file"); + let file = File::open("examples/data/route_guide_db.json").expect("failed to open data file"); let decoded: Vec = serde_json::from_reader(&file).expect("failed to deserialize features"); diff --git a/examples/src/routeguide/server.rs b/examples/src/routeguide/server.rs index caf7154..7760842 100644 --- a/examples/src/routeguide/server.rs +++ b/examples/src/routeguide/server.rs @@ -1,28 +1,30 @@ -mod data; - -use futures::{Stream, StreamExt}; use std::collections::HashMap; use std::hash::{Hash, Hasher}; use std::pin::Pin; use std::sync::Arc; use std::time::Instant; + +use futures::{Stream, StreamExt}; use tokio::sync::mpsc; use tonic::transport::Server; use tonic::{Request, Response, Status}; +use routeguide::route_guide_server::{RouteGuide, RouteGuideServer}; +use routeguide::{Feature, Point, Rectangle, RouteNote, RouteSummary}; + pub mod routeguide { tonic::include_proto!("routeguide"); } -use routeguide::{route_guide_server, Feature, Point, Rectangle, RouteNote, RouteSummary}; +mod data; #[derive(Debug)] -pub struct RouteGuide { +pub struct RouteGuideService { features: Arc>, } #[tonic::async_trait] -impl route_guide_server::RouteGuide for RouteGuide { +impl RouteGuide for RouteGuideService { async fn get_feature(&self, request: Request) -> Result, Status> { println!("GetFeature = {:?}", request); @@ -32,12 +34,7 @@ impl route_guide_server::RouteGuide for RouteGuide { } } - let response = Response::new(Feature { - name: "".to_string(), - location: None, - }); - - Ok(response) + Ok(Response::new(Feature::default())) } type ListFeaturesStream = mpsc::Receiver>; @@ -148,13 +145,13 @@ impl route_guide_server::RouteGuide for RouteGuide { async fn main() -> Result<(), Box> { let addr = "[::1]:10000".parse().unwrap(); - println!("Listening on: {}", addr); + println!("RouteGuideServer listening on: {}", addr); - let route_guide = RouteGuide { + let route_guide = RouteGuideService { features: Arc::new(data::load()), }; - let svc = route_guide_server::RouteGuideServer::new(route_guide); + let svc = RouteGuideServer::new(route_guide); Server::builder().add_service(svc).serve(addr).await?;