feat(docs): Add routeguide tutorial (#21)

This commit is contained in:
Juan Alvarez
2019-10-18 18:02:48 -04:00
committed by Lucio Franco
parent 62101039ce
commit 5d0a795554
5 changed files with 943 additions and 49 deletions
+86 -18
View File
@@ -1,7 +1,11 @@
use futures::TryStreamExt;
use route_guide::{Point, RouteNote};
use futures::stream;
use rand::rngs::ThreadRng;
use rand::Rng;
use route_guide::{Point, Rectangle, RouteNote};
use std::error::Error;
use std::time::{Duration, Instant};
use tokio::timer::Interval;
use tonic::transport::Channel;
use tonic::Request;
pub mod route_guide {
@@ -10,23 +14,55 @@ pub mod route_guide {
use route_guide::client::RouteGuideClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = RouteGuideClient::connect("http://[::1]:10000")?;
async fn print_features(client: &mut RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {
let rectangle = Rectangle {
lo: Some(Point {
latitude: 400000000,
longitude: -750000000,
}),
hi: Some(Point {
latitude: 420000000,
longitude: -730000000,
}),
};
let mut stream = client
.list_features(Request::new(rectangle))
.await?
.into_inner();
while let Some(feature) = stream.message().await? {
println!("NOTE = {:?}", feature);
}
Ok(())
}
async fn run_record_route(client: &mut RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {
let mut rng = rand::thread_rng();
let point_count: i32 = rng.gen_range(2, 100);
let mut points = vec![];
for _ in 0..=point_count {
points.push(random_point(&mut rng))
}
println!("Traversing {} points", points.len());
let request = Request::new(stream::iter(points));
match client.record_route(request).await {
Ok(response) => println!("SUMMARY: {:?}", response.into_inner()),
Err(e) => println!("something went wrong: {:?}", e),
}
Ok(())
}
async fn run_route_chat(client: &mut RouteGuideClient<Channel>) -> Result<(), Box<dyn Error>> {
let start = Instant::now();
let response = client
.get_feature(Request::new(Point {
latitude: 409146138,
longitude: -746188906,
}))
.await?;
println!("FEATURE = {:?}", response);
let outbound = async_stream::stream! {
let mut interval = Interval::new_interval(Duration::from_secs(1));
let mut interval = Interval::new_interval(Duration::from_secs(1));
while let Some(time) = interval.next().await {
let elapsed = time.duration_since(start);
@@ -43,14 +79,46 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
};
let request = Request::new(outbound);
let response = client.route_chat(request).await?;
let mut inbound = response.into_inner();
while let Some(note) = inbound.try_next().await? {
while let Some(note) = inbound.message().await? {
println!("NOTE = {:?}", note);
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = RouteGuideClient::connect("http://[::1]:10000")?;
println!("*** SIMPLE RPC ***");
let response = client
.get_feature(Request::new(Point {
latitude: 409146138,
longitude: -746188906,
}))
.await?;
println!("RESPONSE = {:?}", response);
println!("\n*** SERVER STREAMING ***");
print_features(&mut client).await?;
println!("\n*** CLIENT STREAMING ***");
run_record_route(&mut client).await?;
println!("\n*** BIDIRECTIONAL STREAMING ***");
run_route_chat(&mut client).await?;
Ok(())
}
fn random_point(rng: &mut ThreadRng) -> Point {
let latitude = (rng.gen_range(0, 180) - 90) * 10_000_000;
let longitude = (rng.gen_range(0, 360) - 180) * 10_000_000;
Point {
latitude,
longitude,
}
}
+4 -9
View File
@@ -1,6 +1,5 @@
use serde::Deserialize;
use std::fs::File;
use std::io::prelude::*;
#[derive(Debug, Deserialize)]
struct Feature {
@@ -16,15 +15,11 @@ struct Location {
#[allow(dead_code)]
pub fn load() -> Vec<crate::routeguide::Feature> {
let mut file = File::open("tonic-examples/data/route_guide_db.json")
.ok()
.expect("failed to open data file");
let mut data = String::new();
file.read_to_string(&mut data)
.ok()
.expect("failed to read data file");
let file =
File::open("tonic-examples/data/route_guide_db.json").expect("failed to open data file");
let decoded: Vec<Feature> = serde_json::from_str(&data).unwrap();
let decoded: Vec<Feature> =
serde_json::from_reader(&file).expect("failed to deserialize features");
decoded
.into_iter()
+10 -22
View File
@@ -6,7 +6,7 @@ use std::hash::{Hash, Hasher};
use std::pin::Pin;
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::{mpsc, Mutex};
use tokio::sync::mpsc;
use tonic::transport::Server;
use tonic::{Request, Response, Status};
@@ -18,13 +18,7 @@ use routeguide::{server, Feature, Point, Rectangle, RouteNote, RouteSummary};
#[derive(Debug)]
pub struct RouteGuide {
state: State,
}
#[derive(Debug, Clone)]
struct State {
features: Arc<Vec<Feature>>,
notes: Arc<Mutex<HashMap<Point, Vec<RouteNote>>>>,
}
#[tonic::async_trait]
@@ -32,7 +26,7 @@ impl server::RouteGuide for RouteGuide {
async fn get_feature(&self, request: Request<Point>) -> Result<Response<Feature>, Status> {
println!("GetFeature = {:?}", request);
for feature in &self.state.features[..] {
for feature in &self.features[..] {
if feature.location.as_ref() == Some(request.get_ref()) {
return Ok(Response::new(feature.clone()));
}
@@ -55,11 +49,10 @@ impl server::RouteGuide for RouteGuide {
println!("ListFeatures = {:?}", request);
let (mut tx, rx) = mpsc::channel(4);
let state = self.state.clone();
let features = self.features.clone();
tokio::spawn(async move {
for feature in &state.features[..] {
for feature in &features[..] {
if in_range(feature.location.as_ref().unwrap(), request.get_ref()) {
println!(" => send {:?}", feature);
tx.send(Ok(feature.clone())).await.unwrap();
@@ -96,7 +89,7 @@ impl server::RouteGuide for RouteGuide {
summary.point_count += 1;
// Find features
for feature in &self.state.features[..] {
for feature in &self.features[..] {
if feature.location.as_ref() == Some(&point) {
summary.feature_count += 1;
}
@@ -123,8 +116,8 @@ impl server::RouteGuide for RouteGuide {
) -> Result<Response<Self::RouteChatStream>, Status> {
println!("RouteChat");
let mut notes = HashMap::new();
let stream = request.into_inner();
let state = self.state.clone();
let output = async_stream::try_stream! {
futures::pin_mut!(stream);
@@ -134,11 +127,10 @@ impl server::RouteGuide for RouteGuide {
let location = note.location.clone().unwrap();
let mut notes = state.notes.lock().await;
let notes = notes.entry(location).or_insert(vec![]);
notes.push(note);
let location_notes = notes.entry(location).or_insert(vec![]);
location_notes.push(note);
for note in notes {
for note in location_notes {
yield note.clone();
}
}
@@ -158,11 +150,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Listening on: {}", addr);
let route_guide = RouteGuide {
state: State {
// Load data file
features: Arc::new(data::load()),
notes: Arc::new(Mutex::new(HashMap::new())),
},
features: Arc::new(data::load()),
};
let svc = server::RouteGuideServer::new(route_guide);