1 use std::collections::HashMap;
2 use std::pin::Pin;
3 use std::sync::Arc;
4 use std::time::Instant;
5
6 use tokio::sync::mpsc;
7 use tokio_stream::{wrappers::ReceiverStream, Stream, StreamExt};
8 use tonic::transport::Server;
9 use tonic::{Request, Response, Status};
10
11 use routeguide::route_guide_server::{RouteGuide, RouteGuideServer};
12 use routeguide::{Feature, Point, Rectangle, RouteNote, RouteSummary};
13
14 pub mod routeguide {
15 tonic::include_proto!("routeguide");
16 }
17
18 mod data;
19
20 #[derive(Debug)]
21 pub struct RouteGuideService {
22 features: Arc<Vec<Feature>>,
23 }
24
25 #[tonic::async_trait]
26 impl RouteGuide for RouteGuideService {
get_feature(&self, request: Request<Point>) -> Result<Response<Feature>, Status>27 async fn get_feature(&self, request: Request<Point>) -> Result<Response<Feature>, Status> {
28 println!("GetFeature = {:?}", request);
29
30 for feature in &self.features[..] {
31 if feature.location.as_ref() == Some(request.get_ref()) {
32 return Ok(Response::new(feature.clone()));
33 }
34 }
35
36 Ok(Response::new(Feature::default()))
37 }
38
39 type ListFeaturesStream = ReceiverStream<Result<Feature, Status>>;
40
list_features( &self, request: Request<Rectangle>, ) -> Result<Response<Self::ListFeaturesStream>, Status>41 async fn list_features(
42 &self,
43 request: Request<Rectangle>,
44 ) -> Result<Response<Self::ListFeaturesStream>, Status> {
45 println!("ListFeatures = {:?}", request);
46
47 let (tx, rx) = mpsc::channel(4);
48 let features = self.features.clone();
49
50 tokio::spawn(async move {
51 for feature in &features[..] {
52 if in_range(feature.location.as_ref().unwrap(), request.get_ref()) {
53 println!(" => send {:?}", feature);
54 tx.send(Ok(feature.clone())).await.unwrap();
55 }
56 }
57
58 println!(" /// done sending");
59 });
60
61 Ok(Response::new(ReceiverStream::new(rx)))
62 }
63
record_route( &self, request: Request<tonic::Streaming<Point>>, ) -> Result<Response<RouteSummary>, Status>64 async fn record_route(
65 &self,
66 request: Request<tonic::Streaming<Point>>,
67 ) -> Result<Response<RouteSummary>, Status> {
68 println!("RecordRoute");
69
70 let mut stream = request.into_inner();
71
72 let mut summary = RouteSummary::default();
73 let mut last_point = None;
74 let now = Instant::now();
75
76 while let Some(point) = stream.next().await {
77 let point = point?;
78
79 println!(" ==> Point = {:?}", point);
80
81 // Increment the point count
82 summary.point_count += 1;
83
84 // Find features
85 for feature in &self.features[..] {
86 if feature.location.as_ref() == Some(&point) {
87 summary.feature_count += 1;
88 }
89 }
90
91 // Calculate the distance
92 if let Some(ref last_point) = last_point {
93 summary.distance += calc_distance(last_point, &point);
94 }
95
96 last_point = Some(point);
97 }
98
99 summary.elapsed_time = now.elapsed().as_secs() as i32;
100
101 Ok(Response::new(summary))
102 }
103
104 type RouteChatStream = Pin<Box<dyn Stream<Item = Result<RouteNote, Status>> + Send + 'static>>;
105
route_chat( &self, request: Request<tonic::Streaming<RouteNote>>, ) -> Result<Response<Self::RouteChatStream>, Status>106 async fn route_chat(
107 &self,
108 request: Request<tonic::Streaming<RouteNote>>,
109 ) -> Result<Response<Self::RouteChatStream>, Status> {
110 println!("RouteChat");
111
112 let mut notes = HashMap::new();
113 let mut stream = request.into_inner();
114
115 let output = async_stream::try_stream! {
116 while let Some(note) = stream.next().await {
117 let note = note?;
118
119 let location = note.location.unwrap();
120
121 let location_notes = notes.entry(location).or_insert(vec![]);
122 location_notes.push(note);
123
124 for note in location_notes {
125 yield note.clone();
126 }
127 }
128 };
129
130 Ok(Response::new(Box::pin(output) as Self::RouteChatStream))
131 }
132 }
133
134 #[tokio::main]
main() -> Result<(), Box<dyn std::error::Error>>135 async fn main() -> Result<(), Box<dyn std::error::Error>> {
136 let addr = "[::1]:10000".parse().unwrap();
137
138 println!("RouteGuideServer listening on: {}", addr);
139
140 let route_guide = RouteGuideService {
141 features: Arc::new(data::load()),
142 };
143
144 let svc = RouteGuideServer::new(route_guide);
145
146 Server::builder().add_service(svc).serve(addr).await?;
147
148 Ok(())
149 }
150
151 impl Eq for Point {}
152
in_range(point: &Point, rect: &Rectangle) -> bool153 fn in_range(point: &Point, rect: &Rectangle) -> bool {
154 use std::cmp;
155
156 let lo = rect.lo.as_ref().unwrap();
157 let hi = rect.hi.as_ref().unwrap();
158
159 let left = cmp::min(lo.longitude, hi.longitude);
160 let right = cmp::max(lo.longitude, hi.longitude);
161 let top = cmp::max(lo.latitude, hi.latitude);
162 let bottom = cmp::min(lo.latitude, hi.latitude);
163
164 point.longitude >= left
165 && point.longitude <= right
166 && point.latitude >= bottom
167 && point.latitude <= top
168 }
169
170 /// Calculates the distance between two points using the "haversine" formula.
171 /// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
calc_distance(p1: &Point, p2: &Point) -> i32172 fn calc_distance(p1: &Point, p2: &Point) -> i32 {
173 const CORD_FACTOR: f64 = 1e7;
174 const R: f64 = 6_371_000.0; // meters
175
176 let lat1 = p1.latitude as f64 / CORD_FACTOR;
177 let lat2 = p2.latitude as f64 / CORD_FACTOR;
178 let lng1 = p1.longitude as f64 / CORD_FACTOR;
179 let lng2 = p2.longitude as f64 / CORD_FACTOR;
180
181 let lat_rad1 = lat1.to_radians();
182 let lat_rad2 = lat2.to_radians();
183
184 let delta_lat = (lat2 - lat1).to_radians();
185 let delta_lng = (lng2 - lng1).to_radians();
186
187 let a = (delta_lat / 2f64).sin() * (delta_lat / 2f64).sin()
188 + (lat_rad1).cos() * (lat_rad2).cos() * (delta_lng / 2f64).sin() * (delta_lng / 2f64).sin();
189
190 let c = 2f64 * a.sqrt().atan2((1f64 - a).sqrt());
191
192 (R * c) as i32
193 }
194